Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions PTZControl/PTZControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@
#define TIMER_FOCUS_CHECK 4711
#define TIMER_AUTO_REPEAT 4712
#define TIMER_CLEAR_MEMORY 4713
#define TIMER_HOTKEY_SWITCH_TO 4714 // Used for Hotkeys sequence
#define TIMER_HOTKEY_POSITION 4715
#define TIMER_HOTKEY_SWITCH_BACK 4716

#define TIMER_HOTKEY_DELAY_1 10 // Switch to camera
#define TIMER_HOTKEY_DELAY_2 10 // Set position
#define TIMER_HOTKEY_DELAY_3 750 // Switch back

#define FOCUS_CHECK_DELAY 250 // After 250msec we move the focus away from a button.
#define AUTO_REPEAT_DELAY 50 // Autorepeat is on the fastest possible delay of 50msec
Expand Down
Binary file modified PTZControl/PTZControl.rc
Binary file not shown.
9 changes: 7 additions & 2 deletions PTZControl/PTZControl.sln
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30804.86
# Visual Studio Version 18
VisualStudioVersion = 18.1.11312.151 d18.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PTZControl", "PTZControl.vcxproj", "{2E2437DA-35E2-4D0D-B1DF-26E1DFEE1FB9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5F57E0AA-D4E2-43EA-8450-C89568C6BEBC}"
ProjectSection(SolutionItems) = preProject
..\README.md = ..\README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Expand Down
8 changes: 4 additions & 4 deletions PTZControl/PTZControl.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,29 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>Static</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<PlatformToolset>v145</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>Static</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>Static</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<PlatformToolset>v145</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>Static</UseOfMfc>
Expand Down
76 changes: 74 additions & 2 deletions PTZControl/PTZControlDlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ CPTZControlDlg::CPTZControlDlg(CWnd* pParent /*=nullptr*/)
, m_iNumWebCams(0)
, m_evTerminating(FALSE,TRUE)
, m_pGuardThread(nullptr)
, m_iHotKeyCurrentCam{ 0 }
, m_iHotKeyNextCam{ 0 }
, m_iHotKeyPosition{ 0 }
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_hAccel = ::LoadAccelerators(AfxFindResourceHandle(IDR_ACCELERATOR, RT_ACCELERATOR), MAKEINTRESOURCE(IDR_ACCELERATOR));
Expand Down Expand Up @@ -339,6 +342,7 @@ BEGIN_MESSAGE_MAP(CPTZControlDlg, CDialogEx)
ON_BN_UNPUSHED(IDC_BT_LEFT, &CPTZControlDlg::OnBtUnpushed)
ON_BN_UNPUSHED(IDC_BT_RIGHT, &CPTZControlDlg::OnBtUnpushed)
ON_WM_TIMER()
ON_WM_HOTKEY()
END_MESSAGE_MAP()


Expand Down Expand Up @@ -590,6 +594,26 @@ BOOL CPTZControlDlg::OnInitDialog()
AfxMessageBox(IDP_ERR_NO_CAMERA, MB_ICONERROR);
}

//-------------Register hotkeys-----------------------------------------

for (int iWebCam = 0; iWebCam<(m_iNumWebCams==0 ? 1 : m_iNumWebCams); ++iWebCam)
{
for (int iPreset = 0; iPreset<CWebcamController::NUM_PRESETS; ++iPreset)
{
if (::RegisterHotKey(
GetSafeHwnd(),
10*(iWebCam+1)+iPreset,
(iWebCam==0 ? (MOD_WIN) :
iWebCam==1 ? (MOD_WIN|MOD_CONTROL) :
iWebCam==2 ? (MOD_WIN|MOD_ALT) : 0),
VK_NUMPAD0+iPreset)==0)
{
auto dwError = ::GetLastError();
TRACE(_T(__FUNCTION__) _T(" RegisterHotKey failed with %d"),dwError);
}
}
}

//---------------------------------------------------------------------
// ADJUST THE DIALOG

Expand Down Expand Up @@ -649,7 +673,7 @@ BOOL CPTZControlDlg::OnInitDialog()
EnableToolTips(TRUE);

// Start a guard thread that takes care about a blocking app.
if (!theApp.m_bNoGuard)
if (!theApp.m_bNoGuard)
m_pGuardThread = AfxBeginThread(&GuardThread,this);

// Set a time to move the focus to the parent window
Expand Down Expand Up @@ -729,6 +753,19 @@ void CPTZControlDlg::OnClose()
theApp.WriteProfileInt(REG_WINDOW,REG_WINDOW_POSX,rect.left);
theApp.WriteProfileInt(REG_WINDOW,REG_WINDOW_POSY,rect.top);

//-------------Register hotkeys-----------------------------------------

for (int iWebCam = 0; iWebCam<(m_iNumWebCams==0 ? 1 : m_iNumWebCams); ++iWebCam)
{
for (int iPreset = 0; iPreset<CWebcamController::NUM_PRESETS; ++iPreset)
{
::UnregisterHotKey(
GetSafeHwnd(),
10*(iWebCam+1)+iPreset
);
}
}

DestroyWindow();
}

Expand Down Expand Up @@ -802,6 +839,14 @@ BOOL CPTZControlDlg::OnBtPreset(UINT nId)
return TRUE;
}

void CPTZControlDlg::OnHotKey(UINT nId, UINT nMod, UINT nKey)
{
m_iHotKeyCurrentCam = m_iCurrentWebCam;
m_iHotKeyNextCam = nId/10-1; // Base 10 = webcam 1
m_iHotKeyPosition = nId%10; // Position 0 = home, 1=mem pos1, etc.
SetTimer(TIMER_HOTKEY_SWITCH_TO, TIMER_HOTKEY_DELAY_1,nullptr);
}

BOOL CPTZControlDlg::OnBtWebCam(UINT nId)
{
SetActiveCam(nId==IDC_BT_WEBCAM1 ? 0 :
Expand Down Expand Up @@ -880,7 +925,34 @@ void CPTZControlDlg::OnSetFocus(CWnd* pOldWnd)

void CPTZControlDlg::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == TIMER_FOCUS_CHECK)
// Timer seuqnce
// - TIMER_HOTKEY_SWITCH_TO
// - TIMER_HOTKEY_POSITION
// - TIMER_HOTKEY_SWITCH_BACK
if (nIDEvent==TIMER_HOTKEY_SWITCH_TO)
{
KillTimer(TIMER_HOTKEY_SWITCH_TO);
SetActiveCam(m_iHotKeyNextCam);
SetTimer(TIMER_HOTKEY_POSITION,TIMER_HOTKEY_DELAY_2,nullptr);
}
else if (nIDEvent==TIMER_HOTKEY_POSITION)
{
KillTimer(TIMER_HOTKEY_POSITION);
if (m_iHotKeyPosition>=0 && m_iHotKeyPosition<CWebcamController::NUM_PRESETS+1)
{
if (m_iHotKeyPosition==0)
CPTZControlDlg::OnBtHome();
else
CPTZControlDlg::OnBtPreset(m_btPreset[m_iHotKeyPosition-1].GetDlgCtrlID());
}
SetTimer(TIMER_HOTKEY_SWITCH_BACK,TIMER_HOTKEY_DELAY_3,nullptr);
}
else if (nIDEvent==TIMER_HOTKEY_SWITCH_BACK)
{
KillTimer(TIMER_HOTKEY_SWITCH_BACK);
SetActiveCam(m_iHotKeyCurrentCam);
}
else if (nIDEvent == TIMER_FOCUS_CHECK)
{
CWnd* pWndFocus = GetFocus();
if (pWndFocus &&
Expand Down
15 changes: 14 additions & 1 deletion PTZControl/PTZControlDlg.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
#include "resource.h"
#include "ExtensionUnit.h"

/////////////////////////////////////////////////////////////////////////////
// Hotkey definitions for 0 (Home), and memory positions 1-8
// We use it for 3 WebCams
// We use offset 10, for each camera, and modifier positions 0-8
// 0 = home, 1-8 = memory slots 1-8
// 23 = Camera 2 memory position 3, 10 = Camera 1, Home position


//////////////////////////////////////////////////////////////////////////////////////////
// CPTZButton

Expand Down Expand Up @@ -113,6 +121,11 @@ class CPTZControlDlg : public CDialogEx
CWinThread* m_pGuardThread;
static UINT AFX_CDECL GuardThread(LPVOID hWnd); // AFX_THREADPROC

// Hotkey perset, used by timer to switch to a camera and memory position
int m_iHotKeyCurrentCam;
int m_iHotKeyNextCam;
int m_iHotKeyPosition;

// Implementation
protected:
HICON m_hIcon;
Expand All @@ -133,7 +146,7 @@ class CPTZControlDlg : public CDialogEx
afx_msg LRESULT OnNcHitTest(CPoint point);
afx_msg void OnBtMemory();
afx_msg BOOL OnBtPreset(UINT nId);

afx_msg void OnHotKey(UINT nId, UINT nMod, UINT nKey);
void ResetMemButton();

afx_msg BOOL OnBtWebCam(UINT nId);
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ If you click on a direction button once, the motor is turned on and off again af
If the direction button remains pressed, the motor remains switched on for the corresponding direction until the button is released again.
This control seems more effective and accurate to me and is the standard. The disadvantage is that if the timer interval is too small, the camera does not react immediately when a button is clicked. But since precision was more important to me because our camera is installed relatively far away from the podium, I use this setting with a 70msec timer.

## Hotkeys
## Normal Hotkeys
The program has serveral hotkeys that allows a control without the mouse when it has the focus.
- Pan-Tilt control with Left, Right, Up, Down keys.
- Home position with Num-0, Home keys.
Expand All @@ -82,6 +82,19 @@ The program has serveral hotkeys that allows a control without the mouse when it
- Select Camera 1. Alt+1, Alt+Num-1, Alt+Page-Up
- Select Camera 2. Alt+2, Alt+Num-2, Alt+Page-Down

## Global Hotkeys
There are also global hotkeys defined. They work from any active program. Normal hotkeys work only as long as the PTZControl program has the input focus. All global hotkeys use the Windows key in combination with Ctrl+Alt key. The global hotkeys defined are:
- For camera 1
- Home position => Windows-Key + 0 (on the numeric key pad)
- Memory Position 1-8 => Windows-Key + 1-8 (on the numeric key pad)
- For camera 2
- Home position => Windows-Key + Ctrl + 0 (on the numeric key pad)
- Memory Position 1-8 => Windows-Key + Ctrl + 1-8 (on the numeric key pad)
- For camera 3
- Home position => Windows-Key + Alt + 0 (on the numeric key pad)
- Memory Position 1-8 => Windows-Key + Alt + 1-8 (on the numeric key pad)
If camera 2/3 are not available the hotkeys are ignored and not defined.


## Command Line Options
A few options can be set from the command line. Command-line switches override the settings in the registry.
Expand Down