emu48plus-mirror/source/keymacro.c
Gwenhael Le Moine bdab3ead6a
fd -e c -e h -e C -e H -x sed -i 's|^M||g'
Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
2024-04-01 17:27:54 +02:00

337 lines
8 KiB
C

/*
* Keymacro.c
*
* This file is part of Emu48
*
* Copyright (C) 2004 Christoph Gießelink
*
*/
#include "pch.h"
#include "resource.h"
#include "emu48.h"
#include "kml.h"
#define KEYMACROHEAD "Emu-KeyMacro" // macro signature
#define MIN_SPEED 0
#define MAX_SPEED 500
typedef struct
{
DWORD dwTime; // elapsed time
DWORD dwKeyEvent; // key code
} KeyData;
INT nMacroState = MACRO_OFF;
INT nMacroTimeout = MIN_SPEED;
BOOL bMacroRealSpeed = TRUE;
DWORD dwMacroMinDelay = 0; // minimum macro play key hold time in ms
static DWORD dwTimeRef;
static HANDLE hMacroFile = INVALID_HANDLE_VALUE;
static HANDLE hEventPlay = NULL;
static HANDLE hThreadEv = NULL;
static VOID InitializeOFN(LPOPENFILENAME ofn)
{
ZeroMemory((LPVOID)ofn, sizeof(OPENFILENAME));
ofn->lStructSize = sizeof(OPENFILENAME);
ofn->hwndOwner = hWnd;
ofn->Flags = OFN_EXPLORER|OFN_HIDEREADONLY;
return;
}
//
// thread playing keys
//
static DWORD WINAPI EventThread(LPVOID pParam)
{
DWORD dwRead = 0;
DWORD dwData = 0,dwTime = 0;
while (WaitForSingleObject(hEventPlay,dwTime) == WAIT_TIMEOUT)
{
if (dwRead != 0) // data read
{
UINT nIn = (dwData >> 0) & 0xFFFF;
UINT nOut = (dwData >> 16) & 0xFF;
BOOL bPress = (dwData >> 24) & 0xFF;
PlayKey(nOut,nIn,bPress);
}
dwTime = nMacroTimeout; // set default speed
while (TRUE)
{
// read next data element
if ( !ReadFile(hMacroFile,&dwData,sizeof(dwData),&dwRead,NULL)
|| dwRead != sizeof(dwData))
{
// play record empty -> quit
PostMessage(hWnd,WM_COMMAND,ID_TOOL_MACRO_STOP,0);
return 0; // exit on file end
}
if ((dwData & 0x80000000) != 0) // time information
{
if (bMacroRealSpeed) // realspeed from data
{
dwTime = dwData & 0x7FFFFFFF;
}
continue;
}
// hold the key state the minimum macro play key hold time
if (dwTime < dwMacroMinDelay) dwTime = dwMacroMinDelay;
dwTime -= dwKeyMinDelay; // remove the actual key hold time
// set negative number to zero
if ((dwTime & 0x80000000) != 0) dwTime = 0;
break; // got key information
}
}
return 0; // exit on stop
UNREFERENCED_PARAMETER(pParam);
}
//
// callback function for recording keys
//
VOID KeyMacroRecord(BOOL bPress, UINT out, UINT in)
{
if (nMacroState == MACRO_NEW) // save key event
{
KeyData Data;
DWORD dwWritten;
dwWritten = GetTickCount(); // time reference
Data.dwTime = (dwWritten - dwTimeRef);
Data.dwTime |= 0x80000000; // set time marker
dwTimeRef = dwWritten;
Data.dwKeyEvent = (bPress & 0xFF);
Data.dwKeyEvent = (Data.dwKeyEvent << 8) | (out & 0xFF);
Data.dwKeyEvent = (Data.dwKeyEvent << 16) | (in & 0xFFFF);
// save key event in file
WriteFile(hMacroFile,&Data,sizeof(Data),&dwWritten,NULL);
_ASSERT(dwWritten == sizeof(Data));
}
return;
}
//
// message handler for save new keyboard macro
//
LRESULT OnToolMacroNew(VOID)
{
TCHAR szMacroFile[MAX_PATH];
OPENFILENAME ofn;
DWORD dwExtensionLength,dwWritten;
// get filename for saving
InitializeOFN(&ofn);
ofn.lpstrFilter =
_T("Keyboard Macro Files (*.MAC)\0*.MAC\0")
_T("All Files (*.*)\0*.*\0");
ofn.lpstrDefExt = _T("MAC");
ofn.nFilterIndex = 1;
ofn.lpstrFile = szMacroFile;
ofn.lpstrFile[0] = 0;
ofn.nMaxFile = ARRAYSIZEOF(szMacroFile);
ofn.Flags |= OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT;
if (GetSaveFileName(&ofn) == FALSE) return 0;
// open file for writing
hMacroFile = CreateFile(szMacroFile,
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hMacroFile == INVALID_HANDLE_VALUE) return 0;
// write header
WriteFile(hMacroFile,KEYMACROHEAD,sizeof(KEYMACROHEAD) - 1,&dwWritten,NULL);
_ASSERT(dwWritten == (DWORD) strlen(KEYMACROHEAD));
// write extension length
dwExtensionLength = 0; // no extension
WriteFile(hMacroFile,&dwExtensionLength,sizeof(dwExtensionLength),&dwWritten,NULL);
_ASSERT(dwWritten == sizeof(dwExtensionLength));
nMacroState = MACRO_NEW;
MessageBox(hWnd,
_T("Press OK to begin to record the Macro."),
_T("Macro Recorder"),
MB_OK|MB_ICONINFORMATION);
dwTimeRef = GetTickCount(); // time reference
return 0;
}
//
// message handler for play keyboard macro
//
LRESULT OnToolMacroPlay(VOID)
{
BYTE byHeader[sizeof(KEYMACROHEAD)-1];
TCHAR szMacroFile[MAX_PATH];
OPENFILENAME ofn;
DWORD dwExtensionLength,dwRead,dwThreadId;
InitializeOFN(&ofn);
ofn.lpstrFilter =
_T("Keyboard Macro Files (*.MAC)\0*.MAC\0")
_T("All Files (*.*)\0*.*\0");
ofn.lpstrDefExt = _T("MAC");
ofn.nFilterIndex = 1;
ofn.lpstrFile = szMacroFile;
ofn.lpstrFile[0] = 0;
ofn.nMaxFile = ARRAYSIZEOF(szMacroFile);
ofn.Flags |= OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST;
if (GetOpenFileName(&ofn) == FALSE) return 0;
// open file for Reading
hMacroFile = CreateFile(szMacroFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hMacroFile == INVALID_HANDLE_VALUE) return 0;
// read header
ReadFile(hMacroFile,byHeader,sizeof(byHeader),&dwRead,NULL);
if ( dwRead != sizeof(byHeader)
|| memcmp(byHeader,KEYMACROHEAD,dwRead) != 0)
{
MessageBox(hWnd,
_T("Wrong keyboard macro file format."),
_T("Macro Recorder"),
MB_OK|MB_ICONSTOP);
CloseHandle(hMacroFile);
return 0;
}
// read extension length
ReadFile(hMacroFile,&dwExtensionLength,sizeof(dwExtensionLength),&dwRead,NULL);
if (dwRead != sizeof(dwExtensionLength))
{
CloseHandle(hMacroFile);
return 0;
}
// read extension
while (dwExtensionLength-- > 0)
{
BYTE byData;
ReadFile(hMacroFile,&byData,sizeof(byData),&dwRead,NULL);
if (dwRead != sizeof(byData))
{
CloseHandle(hMacroFile);
return 0;
}
}
// event for quit playing
hEventPlay = CreateEvent(NULL,FALSE,FALSE,NULL);
nMacroState = MACRO_PLAY;
// start playing thread
VERIFY(hThreadEv = CreateThread(NULL,0,&EventThread,NULL,0,&dwThreadId));
return 0;
}
//
// message handler for stop recording/playing
//
LRESULT OnToolMacroStop(VOID)
{
if (nMacroState != MACRO_OFF)
{
if (hEventPlay) // playing keys
{
// stop playing thread
SetEvent(hEventPlay); // quit play loop
WaitForSingleObject(hThreadEv,INFINITE);
CloseHandle(hThreadEv);
hThreadEv = NULL;
CloseHandle(hEventPlay); // close playing keys event
hEventPlay = NULL;
}
// macro file open
if (hMacroFile != INVALID_HANDLE_VALUE) CloseHandle(hMacroFile);
nMacroState = MACRO_OFF;
}
return 0;
}
//
// activate/deactivate slider
//
static VOID SliderEnable(HWND hDlg,BOOL bEnable)
{
EnableWindow(GetDlgItem(hDlg,IDC_MACRO_SLOW),bEnable);
EnableWindow(GetDlgItem(hDlg,IDC_MACRO_FAST),bEnable);
EnableWindow(GetDlgItem(hDlg,IDC_MACRO_SLIDER),bEnable);
return;
}
//
// Macro settings dialog
//
static INT_PTR CALLBACK MacroProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
// set slider
SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_SETRANGE,FALSE,MAKELONG(0,MAX_SPEED-MIN_SPEED));
SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_SETTICFREQ,MAX_SPEED/10,0);
SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_SETPOS,TRUE,MAX_SPEED-nMacroTimeout);
// set button
CheckDlgButton(hDlg,bMacroRealSpeed ? IDC_MACRO_REAL : IDC_MACRO_MANUAL,BST_CHECKED);
SliderEnable(hDlg,!bMacroRealSpeed);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_MACRO_REAL:
SliderEnable(hDlg,FALSE);
return TRUE;
case IDC_MACRO_MANUAL:
SliderEnable(hDlg,TRUE);
return TRUE;
case IDOK:
// get macro data
nMacroTimeout = MAX_SPEED - (INT) SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_GETPOS,0,0);
bMacroRealSpeed = IsDlgButtonChecked(hDlg,IDC_MACRO_REAL);
// no break
case IDCANCEL:
EndDialog(hDlg, LOWORD(wParam));
}
break;
}
return FALSE;
UNREFERENCED_PARAMETER(lParam);
}
LRESULT OnToolMacroSettings(VOID)
{
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_MACROSET), hWnd, (DLGPROC)MacroProc) == -1)
AbortMessage(_T("Macro Dialog Box Creation Error !"));
return 0;
}