⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lakeymainwindow.cpp

📁 Lakey这是一个免费的CW练习/收/发软件
💻 CPP
字号:
#include "StdAfx.h"
#include "lakeymainwindow.h"

#include "Mmreg.h"
#include "dsound.h"
#include "math.h"
#include "stdio.h"

#include "LakeySetting.h"
#include "SinSound.h"
#include "EventManagerWin32.h"
#include "LaButton.h"
#include "LaJournalPanel.h"
#include "LaLabel.h"
#include "LaLine.h"
#include "LaWaveCapture.h"

#include <assert.h>

#define SAFE_DELETE(x)		if (x) { delete x; x = NULL; }
#define SAFE_DELETE_DC(h)	if (h) { DeleteDC(h); h = NULL; }

#define JOIN_SAFELY(ht)								\
{													\
	if (NULL != ht)									\
	{												\
		DWORD nExitCode_j = -1;						\
		if (GetExitCodeThread(ht, &nExitCode_j))	\
			if (STILL_ACTIVE == nExitCode_j)		\
				WaitForSingleObject(ht, INFINITE);	\
	}												\
}

CLakeyMainWindow::CLakeyMainWindow(HWND hWnd, CLakeySetting* pSetting)
: CEventDispatcherWin32(hWnd)
{
	m_pSetting = pSetting;

	m_pFont = new CFont("Arial", 12, CFont::THIN);
	m_pBtCw = CreateButton(&m_pSetting->m_oCwKeyButton);
	m_pBtSendPause = CreateButton(&m_pSetting->m_oSendPauseButton);
	m_pBtSendFile = CreateButton(&m_pSetting->m_oSendFileButton);

	m_pJpSend = CreateJournalPanel(&m_pSetting->m_oSendJournalRect, m_pSetting->m_nLongHit / m_pSetting->m_nSendJournalPeriod - 5);
	m_pJpRecv = CreateJournalPanel(&m_pSetting->m_oRecvJournalRect, m_pSetting->m_nLongHit / m_pSetting->m_nRecvJournalPeriod - 5);
	m_pRecvDctMonitor = CreateWaveCapture(&m_pSetting->m_oRecvMonitorRect);

	m_pSendCharQueueLabel = CreateLabel(&m_pSetting->m_oSendCharQueueRect, NULL, DT_END_ELLIPSIS|DT_LEFT, "HHH");
	RECT r = m_pSetting->m_oSendJournalRect;
	OffsetRect(&r, 0, -56);
	m_pSendLabel = CreateLabel(&r, "Send", DT_END_ELLIPSIS|DT_LEFT);
	r = m_pSetting->m_oRecvJournalRect;
	OffsetRect(&r, 0, -56);
	m_pRecvLabel = CreateLabel(&r, "Receive", DT_END_ELLIPSIS|DT_LEFT);

	m_pSendJpBorder = CreateLine(m_pSetting->m_oSendCharQueueRect.left, m_pSetting->m_oSendCharQueueRect.bottom + 1,
			m_pSetting->m_oSendCharQueueRect.right, m_pSetting->m_oSendCharQueueRect.bottom + 1);
	m_pRecvJpBorder = CreateLine(m_pSetting->m_oRecvJournalRect.left, m_pSetting->m_oRecvJournalRect.bottom + 1,
			m_pSetting->m_oRecvJournalRect.right, m_pSetting->m_oRecvJournalRect.bottom + 1);

	m_hMorseQueueThread = NULL;
	m_nMorseQueueThreadID = 0;
	m_hMorseJournalThread = NULL;
	m_nMorseJournalThreadID = 0;
	m_hRecvMonitorThread = NULL;
	m_nRecvMonitorThreadID = 0;

	BuildMorseButtons();

	m_pSound = new CSinSound();
	m_pSound->SetFrequency(m_pSetting->m_rBeepFreq);
	m_pSound->SetScale(m_pSetting->m_rBeepVol);

	m_bNeedExit = FALSE;
	m_bCwFlag = FALSE;
	m_nRecvIdleCount = 0;
	m_bPause = FALSE;
	m_bClear = FALSE;

	AddCommandEventControl(this);
}

CLakeyMainWindow::~CLakeyMainWindow(void)
{
	GetWindowRect(GetHWnd(), &m_pSetting->m_oWindowRect);

	m_bNeedExit = TRUE;
	ResumeThread(m_hMorseQueueThread);
	JOIN_SAFELY(m_hMorseQueueThread);
	JOIN_SAFELY(m_hMorseJournalThread);
	JOIN_SAFELY(m_hRecvMonitorThread);

	delete m_pRecvDctMonitor;
	delete m_pRecvJpBorder;
	delete m_pJpRecv;
	delete m_pSendJpBorder;
	delete m_pSendCharQueueLabel;
	delete m_pJpSend;
	delete m_pBtCw;
	delete m_pBtSendPause;
	delete m_pBtSendFile;
	delete m_pSendLabel;
	delete m_pRecvLabel;
	delete m_pSound;
	delete m_pFont;

	for (int i = 0; i < MORSECODECOUNT; ++i)
		delete m_vBtMorse[i];
}

void CLakeyMainWindow::BuildMorseButtons()
{
	RECT r;
	GetWindowRect(GetHWnd(), &r);

	int x = 10;
	int oy = 300;
	int y = oy;
	int nMaxY = r.bottom - r.top - 58;
	int h = 12;
	int w = 58;
	char txt[] = { ' ', ' ', ' ', ' ', ' ', '#', '#', '#', '#', '#', '#', '\0' };

	for (int i = 0; i < MORSECODECOUNT; ++i)
	{
		MORSECODE* p = &(m_pSetting->m_vMorseCode[i]);
		txt[0] = p->nAscCode;
		int nWin = 0x0020;
		for (int j = 0; j < 6; ++j, nWin >>= 1)
		{
			if (nWin & p->nMask)
				txt[j + 5] = (nWin & p->nMorseCode ? '.' : '-');
			else
				txt[j + 5] = ' ';
		}

		m_vBtMorse[i] = CreateButton(txt, x, y, w, h, p->nKeyCode);
		m_vBtMorse[i]->SetUserData(p);

		if ((y += (h + 2)) > nMaxY)
		{
			y = oy;
			x += (6 * w / 5);
		}
	}
}

MORSECODE* CLakeyMainWindow::GetMorseCode(char ch)
{
	for (int i = 0; i < MORSECODECOUNT; ++i)
	{
		MORSECODE* p = &(m_pSetting->m_vMorseCode[i]);
		if (ch == p->nAscCode || ch + ('A' - 'a') == p->nAscCode)
			return p;
	}

	// '_' is default
	return &(m_pSetting->m_vMorseCode[MORSECODECOUNT - 1]);
}

CLaButton* CLakeyMainWindow::CreateButton(const char* pText, int x, int y, int w, int h, int nWantKeyCode)
{
	RECT r;
	r.left = x; r.top = y; r.right = x + w; r.bottom = y + h;

	CLaButton* pButton = new CLaButton(this, pText, &r, CLaButton::BT_NORMAL, m_pFont);
	pButton->SetWantKeyCode(nWantKeyCode);

	AddPaintEventControl(pButton);
	AddMouseMoveEventControl(pButton);
	AddMouseKeyEventControl(pButton);
	AddKeyboardEventControl(pButton);
	pButton->AddMouseKeyEventListener(this);
	pButton->AddKeyboardEventListener(this);

	return pButton;
}

CLaButton* CLakeyMainWindow::CreateButton(const BUTTONMAPPING* pMapping)
{
	return CreateButton(pMapping->vLabel, pMapping->x, pMapping->y, pMapping->w, pMapping->h, pMapping->nKeyCode);
}

CLaJournalPanel* CLakeyMainWindow::CreateJournalPanel(const RECT* pRect, int nMaxShortCount)
{
	CLaJournalPanel* jp = new CLaJournalPanel(this, pRect, m_pSetting->m_vMorseCode, nMaxShortCount, m_pFont);

	AddPaintEventControl(jp);

	return jp;
}

CLaWaveCapture* CLakeyMainWindow::CreateWaveCapture(const RECT* pRect)
{
	CLaWaveCapture* wc = new CLaWaveCapture(this, pRect, 44100, m_pSetting->m_nRecvAnalyzeSamples, this);
	wc->SetFreqRange(m_pSetting->m_nRecvFreqStart, m_pSetting->m_nRecvFreqEnd);
	wc->SetThresholdLevel(m_pSetting->m_rRecvThreshold);

	AddPaintEventControl(wc);

	return wc;
}

CLaLabel* CLakeyMainWindow::CreateLabel(const RECT* pRect, const char* pText, int nStyle, const char* pMutexName/* = NULL */)
{
	CLaLabel* label = new CLaLabel(this, pRect, pText, nStyle, m_pFont, pMutexName);

	AddPaintEventControl(label);

	return label;
}

CLaLine* CLakeyMainWindow::CreateLine(int x1, int y1, int x2, int y2)
{
	CLaLine* line = new CLaLine(this, x1, y1, x2, y2);

	AddPaintEventControl(line);

	return line;
}

BOOL CLakeyMainWindow::Initialize()
{
	m_hMorseQueueThread = CreateThread(NULL, 0, MorseQueueThreadProc, this, CREATE_SUSPENDED, &m_nMorseQueueThreadID);
	if (!m_hMorseQueueThread)
		return FALSE;

	m_hMorseJournalThread = CreateThread(NULL, 0, MorseJournalThreadProc, this, 0, &m_nMorseJournalThreadID);
	if (!m_hMorseJournalThread)
		return FALSE;

	///*
	m_pRecvDctMonitor->Initialize();
	m_hRecvMonitorThread = CreateThread(NULL, 0, RecvMonitorThreadProc, this, 0, &m_nRecvMonitorThreadID);
	if (!m_hRecvMonitorThread)
		return FALSE;
	//	*/

	return m_pSound->Initialize(GetHWnd());
}

void CLakeyMainWindow::GetRect(RECT* r)
{
	GetClientRect(GetHWnd(), r);
}

void CLakeyMainWindow::OnPaint(void* owner, CGraphics* g, const RECT* pRect)
{
}

void CLakeyMainWindow::OnMouseMove(void* owner, int x, int y)
{
}

void CLakeyMainWindow::OnKeyDown(void* owner, int nKeyCode)
{
	if (m_pBtCw == owner)
		CwDown();
	else if (' ' == nKeyCode)
	{
		m_pRecvDctMonitor->Refresh();
	}
}

void CLakeyMainWindow::OnKeyUp(void* owner, int nKeyCode)
{
	if (m_pBtCw == owner)
		CwUp();
	else if (m_pBtSendFile == owner)
	{
		ChooseSendFile();
	}
}

void CLakeyMainWindow::OnMouseKeyDown(void* owner, MouseKeyType nMkt, int x, int y)
{
	if (m_pBtCw == owner)
		CwDown();
	else if (this == owner)
	{
	}
}

void CLakeyMainWindow::OnMouseKeyUp(void* owner, MouseKeyType nMkt, int x, int y)
{
	if (m_pBtCw == owner)
		CwUp();
	else if (m_pBtSendFile == owner)
	{
		ChooseSendFile();
	}
	else if (this == owner)
	{
	}
	else
	{
	}
}

BOOL CLakeyMainWindow::ChooseSendFile()
{
	OPENFILENAME ofn;       // common dialog box structure
	char szFile[260] = "*.txt";       // buffer for file name
	HANDLE hf;              // file handle

	// Initialize OPENFILENAME
	ZeroMemory(&ofn, sizeof(OPENFILENAME));
	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner = GetHWnd();
	ofn.lpstrFile = szFile;
	ofn.nMaxFile = sizeof(szFile);
	ofn.lpstrFilter = "All\0*.*\0Text\0*.TXT\0";
	ofn.nFilterIndex = 1;
	ofn.lpstrFileTitle = NULL;
	ofn.nMaxFileTitle = 0;
	ofn.lpstrInitialDir = NULL;
	ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

	// Display the Open dialog box. 
	if (GetOpenFileName(&ofn))
	{
		hf = CreateFile(ofn.lpstrFile, GENERIC_READ,
			0, (LPSECURITY_ATTRIBUTES) NULL,
			OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
			(HANDLE) NULL);

		char vBuff[256];
		int nRead = -1;
		while(ReadFile(hf, vBuff, sizeof(vBuff), (LPDWORD)&nRead, NULL) && 0 < nRead)
		{
			PushText(vBuff, nRead, 0);
		}

		CloseHandle(hf);
		return TRUE;
	}
	return FALSE;
}

void CLakeyMainWindow::PushText(const char* pBuff, int nSize, int nWordLen)
{
	for (int i = 0; i < nSize; ++i)
	{
		if (m_pSendCharQueueLabel->PushChar(pBuff[i]))
			m_oSendMorseQueue.push(GetMorseCode(pBuff[i]));

		if (0 < nWordLen && 0 == (i + 1) % (nWordLen))
		{
			if (m_pSendCharQueueLabel->PushChar('_'))
				m_oSendMorseQueue.push(GetMorseCode(' '));
		}
	}

	ResumeThread(m_hMorseQueueThread);
}

void CLakeyMainWindow::ClearQueue()
{
	m_bClear = TRUE;
}

BOOL CLakeyMainWindow::OnClick(void* owner)
{
	if (m_pBtCw == owner)
	{
	}
	else if (m_pBtSendPause == owner)
	{
		if (m_bPause = !m_bPause)
			m_pBtSendPause->SetText("Continue");
		else
			m_pBtSendPause->SetText("Pause");

		return TRUE;
	}
	else if (m_pBtSendFile == owner)
	{
	}
	else if (this == owner)
	{
	}
	else
	{
		CLaButton* pMorseBt = (CLaButton *)owner;
		MORSECODE* pMorseCode = (MORSECODE *)pMorseBt->GetUserData();
		if (pMorseCode && MAX_LABEL_TEXT_LEN > m_oSendMorseQueue.size())
		{
			if (m_pSendCharQueueLabel->PushChar(pMorseCode->nAscCode))
			{
				m_oSendMorseQueue.push(pMorseCode);
				ResumeThread(m_hMorseQueueThread);
			}

			return TRUE;
		}
	}

	return FALSE;
}

void CLakeyMainWindow::CwDown()
{
	m_pSound->Play();
	m_bCwFlag = TRUE;
}

void CLakeyMainWindow::CwUp()
{
	m_pSound->Stop();
	m_bCwFlag = FALSE;
}

void CLakeyMainWindow::OnCwEvent(BOOL bCwDown)
{
	if (bCwDown)
		m_nRecvIdleCount = 0;

	if (m_nRecvIdleCount < m_pSetting->m_nRecvIdleLimit)
		m_pJpRecv->Sample(bCwDown);

	m_nRecvIdleCount += m_pSetting->m_nRecvJournalPeriod;
}

void CLakeyMainWindow::OnCommand(void* owner, int nCommId)
{
}

// Threads definition
#define NOTEVALIFNEEDEXIT(expr)	if (!owner->m_bNeedExit) expr

DWORD WINAPI CLakeyMainWindow::MorseQueueThreadProc(LPVOID pOwner)
{
	CLakeyMainWindow* owner = (CLakeyMainWindow *)pOwner;

	while(!owner->m_bNeedExit)
	{
		assert(!owner->m_oSendMorseQueue.empty());

		while(!owner->m_bNeedExit && !owner->m_oSendMorseQueue.empty())
		{
			if (!owner->m_bPause)
			{
				MORSECODE* pMorse = owner->m_oSendMorseQueue.front();
				owner->m_oSendMorseQueue.pop();
				
				if (!owner->m_bClear)
				{
					if ('_' != pMorse->nAscCode)
					{
						int nWindow = pMorse->nMask + 1;
						while((!owner->m_bNeedExit) && (nWindow >>= 1))
						{
							int nHitCount =
								nWindow & pMorse->nMorseCode ? 
									owner->m_pSetting->m_nShortHit : owner->m_pSetting->m_nLongHit;

							owner->CwDown();
							NOTEVALIFNEEDEXIT(Sleep(nHitCount));
							owner->CwUp();
							NOTEVALIFNEEDEXIT(Sleep(owner->m_pSetting->m_nHitDelay));
						}
					}
					else
					{
						NOTEVALIFNEEDEXIT(Sleep(owner->m_pSetting->m_nWordDelay));
					}
				}
				
				owner->m_pSendCharQueueLabel->PopChar();
			}

			if (!owner->m_bClear)
				NOTEVALIFNEEDEXIT(Sleep(owner->m_pSetting->m_nLetterDelay));
		}

		owner->m_bClear = FALSE;
		NOTEVALIFNEEDEXIT(SuspendThread(owner->m_hMorseQueueThread));
	}

	return 0;
}

DWORD WINAPI CLakeyMainWindow::MorseJournalThreadProc(LPVOID pOwner)
{
	CLakeyMainWindow* owner = (CLakeyMainWindow *)pOwner;
	int nIdleCount = 0;

	while(!owner->m_bNeedExit)
	{
		if (owner->m_bCwFlag)
			nIdleCount = 0;

		if (nIdleCount < owner->m_pSetting->m_nSendIdleLimit)
			owner->m_pJpSend->Sample(owner->m_bCwFlag);

		NOTEVALIFNEEDEXIT(Sleep(owner->m_pSetting->m_nSendJournalPeriod));
		nIdleCount += owner->m_pSetting->m_nSendJournalPeriod;
	}

	return 0;
}

DWORD WINAPI CLakeyMainWindow::RecvMonitorThreadProc(LPVOID pOwner)
{
	CLakeyMainWindow* owner = (CLakeyMainWindow *)pOwner;

	while(!owner->m_bNeedExit)
	{
		owner->m_pRecvDctMonitor->Refresh();

		NOTEVALIFNEEDEXIT(Sleep(owner->m_pSetting->m_nRecvJournalPeriod));
	}

	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -