obs/OBSApi/HotkeyControlEx.cpp
jp9000 4a1b9bb1c0 Remove the ability for mouse 1/2 to be hotkeys
This just causes trouble.  I'm terribly sorry to anyone who wanted to
use them but it's just causing trouble for new users
2014-04-23 21:38:48 -07:00

515 lines
16 KiB
C++

/********************************************************************************
Copyright (C) 2012 Hugh Bailey <obs.jim@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
********************************************************************************/
#include "OBSAPI.h"
#include <Xinput.h>
#define XINPUT_GAMEPAD_LEFT_TRIGGER 0x0400
#define XINPUT_GAMEPAD_RIGHT_TRIGGER 0x0800
#define IDT_XINPUT_HOTKEY_TIMER 1337
//basically trying to do the same as the windows default hotkey control, but with mouse button support.
struct HotkeyControlExData
{
DWORD hotkeyVK, modifiers;
DWORD xinputNum, xinputButton;
bool bHasFocus;
long cx,cy;
HFONT hFont;
int fontHeight;
void DrawHotkeyControlEx(HWND hwnd, HDC hDC);
};
inline HotkeyControlExData* GetHotkeyControlExData(HWND hwnd)
{
return (HotkeyControlExData*)GetWindowLongPtr(hwnd, 0);
}
LRESULT CALLBACK HotkeyExProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HotkeyControlExData *control;
switch(message)
{
case WM_NCCREATE:
{
CREATESTRUCT *pCreateData = (CREATESTRUCT*)lParam;
SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_STATICEDGE);
control = (HotkeyControlExData*)malloc(sizeof(HotkeyControlExData));
zero(control, sizeof(HotkeyControlExData));
SetWindowLongPtr(hwnd, 0, (LONG_PTR)control);
control->hotkeyVK = 0;
control->modifiers = 0;
control->xinputNum = 0;
control->xinputButton = 0;
control->cx = pCreateData->cx;
control->cy = pCreateData->cy;
control->hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
return TRUE;
}
case WM_CREATE:
{
control = GetHotkeyControlExData(hwnd);
HDC hDC = GetDC(hwnd);
SIZE size;
SelectObject(hDC, control->hFont);
GetTextExtentPoint32(hDC, TEXT("C"), 1, &size);
control->fontHeight = size.cy;
ReleaseDC(hwnd, hDC);
break;
}
case WM_SETFOCUS:
{
control = GetHotkeyControlExData(hwnd);
InvalidateRect(hwnd, NULL, TRUE);
CreateCaret(hwnd, NULL, 0, control->fontHeight);
control->bHasFocus = true;
int x = GetSystemMetrics(SM_CXEDGE);
int y = GetSystemMetrics(SM_CYEDGE);
SetCaretPos(x-1, y);
ShowCaret(hwnd);
SetTimer(hwnd, IDT_XINPUT_HOTKEY_TIMER, 100, NULL);
break;
}
case WM_KILLFOCUS:
{
control = GetHotkeyControlExData(hwnd);
control->bHasFocus = false;
DestroyCaret();
InvalidateRect(hwnd, NULL, TRUE);
KillTimer(hwnd, IDT_XINPUT_HOTKEY_TIMER);
break;
}
case WM_GETDLGCODE:
return DLGC_WANTCHARS | DLGC_WANTARROWS;
case HKM_SETHOTKEY:
{
control = GetHotkeyControlExData(hwnd);
if(HIWORD(wParam))
{
control->hotkeyVK = 0;
control->modifiers = 0;
control->xinputButton = HIWORD(wParam);
control->xinputNum = LOWORD(wParam);
}
else
{
control->hotkeyVK = LOBYTE(wParam);
control->modifiers = HIBYTE(wParam);
control->xinputButton = 0;
control->xinputNum = 0;
}
InvalidateRect(hwnd, NULL, TRUE);
break;
}
case HKM_GETHOTKEY:
{
control = GetHotkeyControlExData(hwnd);
if(control->xinputButton)
return MAKELONG(control->xinputNum, control->xinputButton);
else
return MAKEWORD(control->hotkeyVK, control->modifiers);
}
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
{
control = GetHotkeyControlExData(hwnd);
if( wParam == VK_RETURN ||
wParam == VK_TAB ||
wParam == VK_DELETE ||
wParam == VK_ESCAPE ||
wParam == VK_LWIN ||
wParam == VK_RWIN ||
wParam == VK_APPS )
{
if(control->hotkeyVK != 0 || control->modifiers != 0)
{
control->hotkeyVK = 0;
control->modifiers = 0;
control->xinputButton = 0;
control->xinputNum = 0;
InvalidateRect(hwnd, NULL, TRUE);
PostMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM)hwnd);
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
DWORD hotkeyVK = 0;
if(wParam != VK_MENU && wParam != VK_SHIFT && wParam != VK_CONTROL)
hotkeyVK = (DWORD)wParam;
DWORD modifiers = 0;
if((GetKeyState(VK_CONTROL) & 0x8000) != 0)
modifiers |= HOTKEYF_CONTROL;
if((GetKeyState(VK_SHIFT) & 0x8000) != 0)
modifiers |= HOTKEYF_SHIFT;
if((GetKeyState(VK_MENU) & 0x8000) != 0)
modifiers |= HOTKEYF_ALT;
bool bExtendedKey = (lParam & 0x01000000) != 0;
if(bExtendedKey)
modifiers |= HOTKEYF_EXT;
if((hotkeyVK && control->hotkeyVK != hotkeyVK) || control->modifiers != modifiers)
{
control->hotkeyVK = hotkeyVK;
control->modifiers = modifiers;
control->xinputButton = 0;
control->xinputNum = 0;
InvalidateRect(hwnd, NULL, TRUE);
PostMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM)hwnd);
}
break;
}
case WM_LBUTTONDOWN:
{
control = GetHotkeyControlExData(hwnd);
if(!control->bHasFocus)
SetFocus(hwnd);
break;;
}
case WM_RBUTTONDOWN:
break;
case WM_MBUTTONDOWN:
case WM_XBUTTONDOWN:
{
control = GetHotkeyControlExData(hwnd);
DWORD modifiers = 0;
if((GetKeyState(VK_CONTROL) & 0x8000) != 0)
modifiers |= HOTKEYF_CONTROL;
if((GetKeyState(VK_SHIFT) & 0x8000) != 0)
modifiers |= HOTKEYF_SHIFT;
if((GetKeyState(VK_MENU) & 0x8000) != 0)
modifiers |= HOTKEYF_ALT;
DWORD hotkeyVK = 0;
switch(message)
{
case WM_LBUTTONDOWN: hotkeyVK = VK_LBUTTON; break;
case WM_RBUTTONDOWN: hotkeyVK = VK_RBUTTON; break;
case WM_MBUTTONDOWN: hotkeyVK = VK_MBUTTON; break;
case WM_XBUTTONDOWN:
if(GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
hotkeyVK = VK_XBUTTON1;
else if(GET_XBUTTON_WPARAM(wParam) == XBUTTON2)
hotkeyVK = VK_XBUTTON2;
}
if(control->hotkeyVK != hotkeyVK || control->modifiers != modifiers)
{
control->hotkeyVK = hotkeyVK;
control->modifiers = modifiers;
control->xinputButton = 0;
control->xinputNum = 0;
InvalidateRect(hwnd, NULL, TRUE);
PostMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM)hwnd);
}
break;
}
case WM_TIMER:
{
control = GetHotkeyControlExData(hwnd);
for(int i = 0; i < 4; ++i)
{
XINPUT_STATE state = { 0 };
if(XInputGetState(i, &state) != ERROR_SUCCESS)
continue;
if(state.Gamepad.bLeftTrigger >= 85)
state.Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_TRIGGER;
if(state.Gamepad.bRightTrigger >= 85)
state.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_TRIGGER;
if(state.Gamepad.wButtons == 0)
continue;
// Continue if more than exactly one button is pressed
if(state.Gamepad.wButtons & (state.Gamepad.wButtons - 1))
continue;
control->hotkeyVK = 0;
control->modifiers = 0;
control->xinputButton = state.Gamepad.wButtons;
control->xinputNum = i;
InvalidateRect(hwnd, NULL, TRUE);
PostMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM)hwnd);
break;
}
break;
}
case WM_PAINT:
{
control = GetHotkeyControlExData(hwnd);
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hwnd, &ps);
control->DrawHotkeyControlEx(hwnd, hDC);
EndPaint(hwnd, &ps);
break;
}
case WM_ERASEBKGND:
{
control = GetHotkeyControlExData(hwnd);
HideCaret(hwnd);
RECT rc;
HDC hDC = GetDC(hwnd);
GetClientRect(hwnd, &rc);
if(IsWindowEnabled(hwnd))
FillRect(hDC, &rc, (HBRUSH)(COLOR_WINDOW+1));
else
FillRect(hDC, &rc, (HBRUSH)(COLOR_BTNFACE+1));
ReleaseDC(hwnd, hDC);
ShowCaret(hwnd);
break;
}
case WM_GETFONT:
{
control = GetHotkeyControlExData(hwnd);
return (LRESULT)control->hFont;
}
case WM_SETFONT:
{
control = GetHotkeyControlExData(hwnd);
control->hFont = (HFONT)wParam;
HDC hDC = GetDC(hwnd);
SIZE size;
SelectObject(hDC, control->hFont);
GetTextExtentPoint32(hDC, TEXT("C"), 1, &size);
control->fontHeight = size.cy;
control->DrawHotkeyControlEx(hwnd, hDC);
ReleaseDC(hwnd, hDC);
break;
}
case WM_ENABLE:
InvalidateRect(hwnd, NULL, TRUE);
//pass through
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
void HotkeyControlExData::DrawHotkeyControlEx(HWND hwnd, HDC hDC)
{
TCHAR lpName[128];
String strText;
if(xinputButton)
{
strText << FormattedString(TEXT("XPad%d "), xinputNum);
switch(xinputButton)
{
case XINPUT_GAMEPAD_DPAD_UP:
strText << "Up";
break;
case XINPUT_GAMEPAD_DPAD_DOWN:
strText << "Down";
break;
case XINPUT_GAMEPAD_DPAD_LEFT:
strText << "Left";
break;
case XINPUT_GAMEPAD_DPAD_RIGHT:
strText << "Right";
break;
case XINPUT_GAMEPAD_START:
strText << "Start";
break;
case XINPUT_GAMEPAD_BACK:
strText << "Back";
break;
case XINPUT_GAMEPAD_LEFT_THUMB:
strText << "LThumb";
break;
case XINPUT_GAMEPAD_RIGHT_THUMB:
strText << "RThumb";
break;
case XINPUT_GAMEPAD_LEFT_SHOULDER:
strText << "LButton";
break;
case XINPUT_GAMEPAD_RIGHT_SHOULDER:
strText << "RButton";
break;
case XINPUT_GAMEPAD_LEFT_TRIGGER:
strText << "LTrigger";
break;
case XINPUT_GAMEPAD_RIGHT_TRIGGER:
strText << "RTrigger";
break;
case XINPUT_GAMEPAD_A:
strText << "A";
break;
case XINPUT_GAMEPAD_B:
strText << "B";
break;
case XINPUT_GAMEPAD_X:
strText << "X";
break;
case XINPUT_GAMEPAD_Y:
strText << "Y";
break;
default:
strText << "Unknown";
}
}
else if(hotkeyVK || modifiers)
{
bool bAdd = false;
if(modifiers & HOTKEYF_CONTROL)
{
GetKeyNameText((LONG)MapVirtualKey(VK_CONTROL, 0) << 16, lpName, 127);
strText << lpName;
bAdd = true;
}
if(modifiers & HOTKEYF_SHIFT)
{
if(bAdd) strText << TEXT(" + ");
GetKeyNameText((LONG)MapVirtualKey(VK_SHIFT, 0) << 16, lpName, 127);
strText << lpName;
bAdd = true;
}
if(modifiers & HOTKEYF_ALT)
{
if(bAdd) strText << TEXT(" + ");
GetKeyNameText((LONG)MapVirtualKey(VK_MENU, 0) << 16, lpName, 127);
strText << lpName;
bAdd = true;
}
if(hotkeyVK)
{
if(bAdd) strText << TEXT(" + ");
if(hotkeyVK <= VK_RBUTTON)
strText << TEXT("Mouse ") << UIntString(hotkeyVK);
else if(hotkeyVK > VK_CANCEL && hotkeyVK <= VK_XBUTTON2)
strText << TEXT("Mouse ") << UIntString(hotkeyVK-1);
else
{
UINT scanCode = MapVirtualKey(hotkeyVK, 0) << 16;
if(modifiers & HOTKEYF_EXT)
scanCode |= 0x01000000;
GetKeyNameText(scanCode, lpName, 128);
strText << lpName;
}
}
}
else
strText << Str("None");
if(bHasFocus)
HideCaret(hwnd);
int x = GetSystemMetrics(SM_CXEDGE);
int y = GetSystemMetrics(SM_CYEDGE);
SelectObject(hDC, hFont);
if(IsWindowEnabled(hwnd))
{
SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
}
else
{
SetBkColor(hDC, GetSysColor(COLOR_BTNFACE));
SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT));
}
TextOut(hDC, x, y, strText, strText.Length());
if(bHasFocus)
ShowCaret(hwnd);
}
void InitHotkeyExControl(HINSTANCE hInstance)
{
WNDCLASS wnd;
wnd.cbClsExtra = 0;
wnd.cbWndExtra = sizeof(LPVOID);
wnd.hbrBackground = NULL;
wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
wnd.hIcon = NULL;
wnd.hInstance = hInstance;
wnd.lpfnWndProc = HotkeyExProc;
wnd.lpszClassName = HOTKEY_CONTROL_EX_CLASS;
wnd.lpszMenuName = NULL;
wnd.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
if(!RegisterClass(&wnd))
CrashError(TEXT("Could not register hotkey control class"));
}