PAD: Process keycodes the same way on Linux and macOS

This commit is contained in:
TellowKrinkle 2022-03-30 22:08:17 -05:00 committed by refractionpcsx2
parent 532a7addd4
commit b90de6d89f
10 changed files with 310 additions and 154 deletions

View File

@ -1262,6 +1262,7 @@ if(NOT PCSX2_CORE)
)
list(APPEND pcsx2OSXSources
Linux/LnxConsolePipe.cpp
Darwin/DarwinKeyCodes.cpp
)
list(APPEND pcsx2FreeBSDSources
Linux/LnxConsolePipe.cpp

View File

@ -0,0 +1,142 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include <Carbon/Carbon.h>
int TranslateOSXtoWXK(u32 keysym)
{
switch (keysym)
{
case kVK_ANSI_A: return 'A';
case kVK_ANSI_S: return 'S';
case kVK_ANSI_D: return 'D';
case kVK_ANSI_F: return 'F';
case kVK_ANSI_H: return 'H';
case kVK_ANSI_G: return 'G';
case kVK_ANSI_Z: return 'Z';
case kVK_ANSI_X: return 'X';
case kVK_ANSI_C: return 'C';
case kVK_ANSI_V: return 'V';
case kVK_ANSI_B: return 'B';
case kVK_ANSI_Q: return 'Q';
case kVK_ANSI_W: return 'W';
case kVK_ANSI_E: return 'E';
case kVK_ANSI_R: return 'R';
case kVK_ANSI_Y: return 'Y';
case kVK_ANSI_T: return 'T';
case kVK_ANSI_1: return '1';
case kVK_ANSI_2: return '2';
case kVK_ANSI_3: return '3';
case kVK_ANSI_4: return '4';
case kVK_ANSI_6: return '6';
case kVK_ANSI_5: return '5';
case kVK_ANSI_Equal: return '=';
case kVK_ANSI_9: return '9';
case kVK_ANSI_7: return '7';
case kVK_ANSI_Minus: return '-';
case kVK_ANSI_8: return '8';
case kVK_ANSI_0: return '0';
case kVK_ANSI_RightBracket: return ']';
case kVK_ANSI_O: return 'O';
case kVK_ANSI_U: return 'U';
case kVK_ANSI_LeftBracket: return '[';
case kVK_ANSI_I: return 'I';
case kVK_ANSI_P: return 'P';
case kVK_ANSI_L: return 'L';
case kVK_ANSI_J: return 'J';
case kVK_ANSI_Quote: return '\'';
case kVK_ANSI_K: return 'K';
case kVK_ANSI_Semicolon: return ';';
case kVK_ANSI_Backslash: return '\\';
case kVK_ANSI_Comma: return ',';
case kVK_ANSI_Slash: return '/';
case kVK_ANSI_N: return 'N';
case kVK_ANSI_M: return 'M';
case kVK_ANSI_Period: return '.';
case kVK_ANSI_Grave: return '`';
case kVK_ANSI_KeypadDecimal: return WXK_NUMPAD_DECIMAL;
case kVK_ANSI_KeypadMultiply: return WXK_NUMPAD_MULTIPLY;
case kVK_ANSI_KeypadPlus: return WXK_NUMPAD_ADD;
case kVK_ANSI_KeypadClear: return WXK_CLEAR;
case kVK_ANSI_KeypadDivide: return WXK_NUMPAD_DIVIDE;
case kVK_ANSI_KeypadEnter: return WXK_NUMPAD_ENTER;
case kVK_ANSI_KeypadMinus: return WXK_NUMPAD_SUBTRACT;
case kVK_ANSI_KeypadEquals: return WXK_NUMPAD_EQUAL;
case kVK_ANSI_Keypad0: return WXK_NUMPAD0;
case kVK_ANSI_Keypad1: return WXK_NUMPAD1;
case kVK_ANSI_Keypad2: return WXK_NUMPAD2;
case kVK_ANSI_Keypad3: return WXK_NUMPAD3;
case kVK_ANSI_Keypad4: return WXK_NUMPAD4;
case kVK_ANSI_Keypad5: return WXK_NUMPAD5;
case kVK_ANSI_Keypad6: return WXK_NUMPAD6;
case kVK_ANSI_Keypad7: return WXK_NUMPAD7;
case kVK_ANSI_Keypad8: return WXK_NUMPAD8;
case kVK_ANSI_Keypad9: return WXK_NUMPAD9;
case kVK_Return: return WXK_RETURN;
case kVK_Tab: return WXK_TAB;
case kVK_Space: return WXK_SPACE;
case kVK_Delete: return WXK_BACK;
case kVK_Escape: return WXK_ESCAPE;
case kVK_Command: return WXK_COMMAND;
case kVK_Shift: return WXK_SHIFT;
case kVK_CapsLock: return WXK_CAPITAL;
case kVK_Option: return WXK_ALT;
case kVK_Control: return WXK_RAW_CONTROL;
case kVK_RightCommand: return WXK_COMMAND;
case kVK_RightShift: return WXK_SHIFT;
case kVK_RightOption: return WXK_ALT;
case kVK_RightControl: return WXK_RAW_CONTROL;
case kVK_Function: return 0;
case kVK_F17: return WXK_F17;
#if wxCHECK_VERSION(3, 1, 0)
case kVK_VolumeUp: return WXK_VOLUME_UP;
case kVK_VolumeDown: return WXK_VOLUME_DOWN;
case kVK_Mute: return WXK_VOLUME_MUTE;
#endif
case kVK_F18: return WXK_F18;
case kVK_F19: return WXK_F19;
case kVK_F20: return WXK_F20;
case kVK_F5: return WXK_F5;
case kVK_F6: return WXK_F6;
case kVK_F7: return WXK_F7;
case kVK_F3: return WXK_F3;
case kVK_F8: return WXK_F8;
case kVK_F9: return WXK_F9;
case kVK_F11: return WXK_F11;
case kVK_F13: return WXK_F13;
case kVK_F16: return WXK_F16;
case kVK_F14: return WXK_F14;
case kVK_F10: return WXK_F10;
case kVK_F12: return WXK_F12;
case kVK_F15: return WXK_F15;
case kVK_Help: return WXK_HELP;
case kVK_Home: return WXK_HOME;
case kVK_PageUp: return WXK_PAGEUP;
case kVK_ForwardDelete: return WXK_DELETE;
case kVK_F4: return WXK_F4;
case kVK_End: return WXK_END;
case kVK_F2: return WXK_F2;
case kVK_PageDown: return WXK_PAGEDOWN;
case kVK_F1: return WXK_F1;
case kVK_LeftArrow: return WXK_LEFT;
case kVK_RightArrow: return WXK_RIGHT;
case kVK_DownArrow: return WXK_DOWN;
case kVK_UpArrow: return WXK_UP;
default:
return 0;
}
}

View File

@ -27,6 +27,8 @@
#include "gui/AppCoreThread.h"
#if defined(__unix__)
#include <X11/keysym.h>
#elif defined(__APPLE__)
#include <Carbon/Carbon.h>
#endif
static std::string GetDumpName()
@ -603,10 +605,17 @@ void GSRenderer::EndCapture()
void GSRenderer::KeyEvent(const HostKeyEvent& e)
{
#if !defined(PCSX2_CORE) && !defined(__APPLE__) // TODO: Add hotkey support on macOS
#if !defined(PCSX2_CORE)
#ifdef _WIN32
m_shift_key = !!(::GetAsyncKeyState(VK_SHIFT) & 0x8000);
m_control_key = !!(::GetAsyncKeyState(VK_CONTROL) & 0x8000);
#elif defined(__APPLE__)
m_shift_key = CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, kVK_Shift)
|| CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, kVK_RightShift);
m_control_key = CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, kVK_Control)
|| CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, kVK_RightControl)
|| CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, kVK_Command)
|| CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, kVK_RightCommand);
#else
switch (e.key)
{
@ -628,12 +637,12 @@ void GSRenderer::KeyEvent(const HostKeyEvent& e)
#if defined(__unix__)
#define VK_F5 XK_F5
#define VK_F6 XK_F6
#define VK_DELETE XK_Delete
#define VK_INSERT XK_Insert
#define VK_PRIOR XK_Prior
#define VK_NEXT XK_Next
#define VK_HOME XK_Home
#elif defined(__APPLE__)
#define VK_F5 kVK_F5
#define VK_DELETE kVK_ForwardDelete
#define VK_NEXT kVK_PageDown
#endif
// NOTE: These are all BROKEN! They mess with GS thread state from the UI thread.
@ -657,7 +666,7 @@ void GSRenderer::KeyEvent(const HostKeyEvent& e)
return;
}
}
#endif // __APPLE__
#endif // PCSX2_CORE
}
void GSRenderer::PurgePool()

View File

@ -26,14 +26,16 @@ struct HostKeyEvent
{
enum class Type
{
NoEvent = 0,
KeyPressed = 1,
KeyReleased = 2,
MousePressed = 3,
MouseReleased = 4,
MouseWheelDown = 5,
MouseWheelUp = 6,
MouseMove = 7,
NoEvent,
KeyPressed,
KeyReleased,
MousePressed,
MouseReleased,
MouseWheelDown,
MouseWheelUp,
MouseMove,
FocusGained,
FocustLost,
};
Type type;

View File

@ -31,6 +31,6 @@ void PADconfigure();
s32 PADfreeze(FreezeAction mode, freezeData* data);
s32 PADsetSlot(u8 port, u8 slot);
#if defined(__unix__)
#if defined(__unix__) || defined(__APPLE__)
void PADWriteEvent(HostKeyEvent& evt);
#endif

View File

@ -220,7 +220,7 @@ HostKeyEvent* PADkeyEvent()
}
}
#endif
#ifdef __unix__
#if defined(__unix__) || defined(__APPLE__)
if (g_ev_fifo.size() == 0)
{
//PAD_LOG("No events in queue, returning empty event");
@ -234,15 +234,10 @@ HostKeyEvent* PADkeyEvent()
AnalyzeKeyEvent(s_event);
//PAD_LOG("Returning Event. Event Type: %d, Key: %d", s_event.type, s_event.key);
return &s_event;
#else // MacOS
s_event = event;
event.type = HostKeyEvent::Type::NoEvent;
event.key = 0;
return &s_event;
#endif
}
#if defined(__unix__)
#if defined(__unix__) || defined(__APPLE__)
void PADWriteEvent(HostKeyEvent& evt)
{
// if (evt.evt != 6) { // Skip mouse move events for logging

View File

@ -64,29 +64,7 @@ static void PressButton(u32 pad, u32 button)
void UpdateKeyboardInput()
{
for (u32 pad = 0; pad < GAMEPAD_NUMBER; pad++)
{
const auto& map = g_conf.keysym_map[pad];
// If we loop over all keys press/release based on current state,
// joystick axes (which have two bound keys) will always go to the later-polled key
// Instead, release all keys first and then set the ones that are pressed
for (const auto& key : map)
g_key_status.release(pad, key.second);
for (const auto& key : map)
{
bool state;
if (key.first >> 16 == 0)
{
state = CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, key.first);
}
else
{
state = CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, (CGMouseButton)(key.first & 0xFFFF));
}
if (state)
PressButton(pad, key.second);
}
}
g_ev_fifo.consume_all(AnalyzeKeyEvent);
}
bool PollForNewKeyboardKeys(u32& pkey)
@ -101,31 +79,103 @@ bool PollForNewKeyboardKeys(u32& pkey)
return true;
}
}
for (auto btn : {kCGMouseButtonLeft, kCGMouseButtonCenter, kCGMouseButtonRight})
{
if (CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, btn))
{
pkey = btn | (1 << 16);
return true;
}
#define CHECK(button, value) \
if (CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, (button))) \
{ \
pkey = (value); \
return true; \
}
CHECK(kCGMouseButtonLeft, 0x10001)
CHECK(kCGMouseButtonCenter, 0x10002)
CHECK(kCGMouseButtonRight, 0x10003)
#undef CHECK
return false;
}
#elif defined(__unix__)
static bool s_grab_input = false;
static bool s_Shift = false;
void UpdateKeyboardInput()
{
HostKeyEvent evt = {};
XEvent E = {0};
// Keyboard input send by PCSX2
g_ev_fifo.consume_all(AnalyzeKeyEvent);
// keyboard input
if (!GSdsp)
return;
while (XPending(GSdsp) > 0)
{
XNextEvent(GSdsp, &E);
// Change the format of the structure to be compatible with GSOpen2
// mode (event come from pcsx2 not X)
evt.type = static_cast<HostKeyEvent::Type>(E.type);
switch (E.type)
{
case MotionNotify:
evt.key = (E.xbutton.x & 0xFFFF) | (E.xbutton.y << 16);
evt.type = HostKeyEvent::Type::MouseMove;
break;
case ButtonRelease:
evt.key = E.xbutton.button | 0x10000;
evt.type = HostKeyEvent::Type::MouseReleased;
break;
case ButtonPress:
evt.key = E.xbutton.button | 0x10000;
evt.type = HostKeyEvent::Type::MousePressed;
break;
case KeyPress:
evt.key = (int)XLookupKeysym(&E.xkey, 0);
evt.type = HostKeyEvent::Type::KeyPressed;
break;
case KeyRelease:
evt.key = (int)XLookupKeysym(&E.xkey, 0);
evt.type = HostKeyEvent::Type::KeyReleased;
default:
continue;
}
AnalyzeKeyEvent(evt);
}
}
bool PollForNewKeyboardKeys(u32& pkey)
{
GdkEvent* ev = gdk_event_get();
if (ev != NULL)
{
if (ev->type == GDK_KEY_PRESS)
{
pkey = ev->key.keyval != GDK_KEY_Escape ? ev->key.keyval : UINT32_MAX;
return true;
}
else if (ev->type == GDK_BUTTON_PRESS)
{
pkey = ev->button.button | 0x10000;
return true;
}
}
return false;
}
#endif
static unsigned int s_previous_mouse_x = 0;
static unsigned int s_previous_mouse_y = 0;
void AnalyzeKeyEvent(HostKeyEvent& evt)
{
KeySym key = (KeySym)evt.key;
int pad = 0;
int index = -1;
for (u32 cpad = 0; cpad < GAMEPAD_NUMBER; cpad++)
{
int tmp_index = get_keyboard_key(cpad, key);
int tmp_index = get_keyboard_key(cpad, evt.key);
if (tmp_index != -1)
{
pad = cpad;
@ -133,17 +183,18 @@ void AnalyzeKeyEvent(HostKeyEvent& evt)
}
}
switch (static_cast<int>(evt.type))
switch (evt.type)
{
case KeyPress:
case HostKeyEvent::Type::KeyPressed:
// Shift F12 is not yet use by pcsx2. So keep it to grab/ungrab input
// I found it very handy vs the automatic fullscreen detection
// 1/ Does not need to detect full-screen
// 2/ Can use a debugger in full-screen
// 3/ Can grab input in window without the need of a pixelated full-screen
if (key == XK_Shift_R || key == XK_Shift_L)
#ifdef __unix__
if (evt.key == XK_Shift_R || evt.key == XK_Shift_L)
s_Shift = true;
if (key == XK_F12 && s_Shift)
if (evt.key == XK_F12 && s_Shift)
{
if (!s_grab_input)
{
@ -158,6 +209,7 @@ void AnalyzeKeyEvent(HostKeyEvent& evt)
XUngrabKeyboard(GSdsp, CurrentTime);
}
}
#endif
if (index != -1)
PressButton(pad, index);
@ -165,38 +217,42 @@ void AnalyzeKeyEvent(HostKeyEvent& evt)
//PAD_LOG("Key pressed:%d", index);
event.type = HostKeyEvent::Type::KeyPressed;
event.key = key;
event.key = evt.key;
break;
case KeyRelease:
if (key == XK_Shift_R || key == XK_Shift_L)
case HostKeyEvent::Type::KeyReleased:
#ifdef __unix__
if (evt.key == XK_Shift_R || evt.key == XK_Shift_L)
s_Shift = false;
#endif
if (index != -1)
g_key_status.release(pad, index);
event.type = HostKeyEvent::Type::KeyReleased;
event.key = key;
event.key = evt.key;
break;
case FocusIn:
case HostKeyEvent::Type::FocusGained:
break;
case FocusOut:
case HostKeyEvent::Type::FocustLost:
#ifdef __unix__
s_Shift = false;
#endif
break;
case ButtonPress:
case HostKeyEvent::Type::MousePressed:
if (index != -1)
g_key_status.press(pad, index);
break;
case ButtonRelease:
case HostKeyEvent::Type::MouseReleased:
if (index != -1)
g_key_status.release(pad, index);
break;
case MotionNotify:
case HostKeyEvent::Type::MouseMove:
// FIXME: How to handle when the mouse does not move, no event generated!!!
// 1/ small move == no move. Cons : can not do small movement
// 2/ use a watchdog timer thread
@ -253,63 +309,10 @@ void AnalyzeKeyEvent(HostKeyEvent& evt)
}
break;
}
}
void UpdateKeyboardInput()
{
HostKeyEvent evt = {};
XEvent E = {0};
// Keyboard input send by PCSX2
g_ev_fifo.consume_all(AnalyzeKeyEvent);
// keyboard input
if (!GSdsp)
return;
while (XPending(GSdsp) > 0)
{
XNextEvent(GSdsp, &E);
// Change the format of the structure to be compatible with GSOpen2
// mode (event come from pcsx2 not X)
evt.type = static_cast<HostKeyEvent::Type>(E.type);
switch (E.type)
{
case MotionNotify:
evt.key = (E.xbutton.x & 0xFFFF) | (E.xbutton.y << 16);
case HostKeyEvent::Type::NoEvent:
case HostKeyEvent::Type::MouseWheelDown:
case HostKeyEvent::Type::MouseWheelUp:
break;
case ButtonRelease:
case ButtonPress:
evt.key = E.xbutton.button;
break;
default:
evt.key = (int)XLookupKeysym(&E.xkey, 0);
}
AnalyzeKeyEvent(evt);
}
}
bool PollForNewKeyboardKeys(u32& pkey)
{
GdkEvent* ev = gdk_event_get();
if (ev != NULL)
{
if (ev->type == GDK_KEY_PRESS)
{
pkey = ev->key.keyval != GDK_KEY_Escape ? ev->key.keyval : UINT32_MAX;
return true;
}
else if (ev->type == GDK_BUTTON_PRESS)
{
pkey = ev->button.button;
return true;
}
}
return false;
}
#endif

View File

@ -25,14 +25,16 @@ static std::string KeyName(int pad, int key, int keysym)
{
switch (keysym & 0xFFFF)
{
case kCGMouseButtonLeft:
case 0:
return "Mouse ???";
case 1:
return "Mouse Left";
case kCGMouseButtonRight:
return "Mouse Right";
case kCGMouseButtonCenter:
case 2:
return "Mouse Middle";
case 3:
return "Mouse Right";
default: // Use only number for extra button
return "Mouse " + std::to_string(keysym & 0xFFFF);
return "Mouse " + std::to_string((keysym & 0xFFFF) + 1);
}
}
@ -167,12 +169,12 @@ static std::string KeyName(int pad, int key, int keysym)
static std::string KeyName(int pad, int key, int keysym)
{
// Mouse
if (keysym < 10)
if (keysym >> 16)
{
switch (keysym)
switch (keysym & 0xFFFF)
{
case 0:
return "";
return "Mouse ???";
case 1:
return "Mouse Left";
case 2:
@ -180,7 +182,7 @@ static std::string KeyName(int pad, int key, int keysym)
case 3:
return "Mouse Right";
default: // Use only number for extra button
return "Mouse " + std::to_string(keysym);
return "Mouse " + std::to_string((keysym & 0xFFFF) + 1);
}
}

View File

@ -153,9 +153,11 @@ protected:
wxIMPLEMENT_DYNAMIC_CLASS( Pcsx2AppMethodEvent, pxActionEvent );
#ifdef __WXMSW__
extern int TranslateVKToWXK( u32 keysym );
#elif defined( __WXGTK__ )
extern int TranslateGDKtoWXK( u32 keysym );
extern int TranslateVKToWXK(u32 keysym);
#elif defined(__WXGTK__)
extern int TranslateGDKtoWXK(u32 keysym);
#elif defined(__APPLE__)
extern int TranslateOSXtoWXK(u32 keysym);
#endif
void Pcsx2App::PadKeyDispatch(const HostKeyEvent& ev)
@ -166,9 +168,9 @@ void Pcsx2App::PadKeyDispatch(const HostKeyEvent& ev)
#ifdef __WXMSW__
const int vkey = TranslateVKToWXK(ev.key);
#elif defined( __WXMAC__ )
const int vkey = wxCharCodeWXToOSX( (wxKeyCode) ev.key );
const int vkey = TranslateOSXtoWXK(ev.key);
#elif defined( __WXGTK__ )
const int vkey = TranslateGDKtoWXK( ev.key );
const int vkey = TranslateGDKtoWXK(ev.key);
#else
# error Unsupported Target Platform.
#endif

View File

@ -397,24 +397,24 @@ void GSPanel::OnMouseEvent( wxMouseEvent& evt )
DoShowMouse();
}
#if defined(__unix__)
#if defined(__unix__) || defined(__APPLE__)
// HACK2: In gsopen2 there is one event buffer read by both wx/gui and pad. Wx deletes
// the event before the pad see it. So you send key event directly to the pad.
HostKeyEvent event;
// FIXME how to handle double click ???
if (evt.ButtonDown())
{
event.type = static_cast<HostKeyEvent::Type>(4); // X equivalent of ButtonPress
event.key = evt.GetButton();
event.type = HostKeyEvent::Type::MousePressed;
event.key = evt.GetButton() | 0x10000;
}
else if (evt.ButtonUp())
{
event.type = static_cast<HostKeyEvent::Type>(5); // X equivalent of ButtonRelease
event.key = evt.GetButton();
event.type = HostKeyEvent::Type::MouseReleased;
event.key = evt.GetButton() | 0x10000;
}
else if (evt.Moving() || evt.Dragging())
{
event.type = static_cast<HostKeyEvent::Type>(6); // X equivalent of MotionNotify
event.type = HostKeyEvent::Type::MouseMove;
long x, y;
evt.GetPosition(&x, &y);
@ -464,15 +464,15 @@ void GSPanel::OnKeyDownOrUp( wxKeyEvent& evt )
// to the APP level message handler, which in turn routes them right back here -- yes it's
// silly, but oh well).
#if defined(__unix__)
#if defined(__unix__) || defined(__APPLE__)
// HACK2: In gsopen2 there is one event buffer read by both wx/gui and pad. Wx deletes
// the event before the pad see it. So you send key event directly to the pad.
HostKeyEvent event;
event.key = evt.GetRawKeyCode();
if (evt.GetEventType() == wxEVT_KEY_UP)
event.type = static_cast<HostKeyEvent::Type>(3); // X equivalent of KEYRELEASE;
event.type = HostKeyEvent::Type::KeyReleased;
else if (evt.GetEventType() == wxEVT_KEY_DOWN)
event.type = static_cast<HostKeyEvent::Type>(2); // X equivalent of KEYPRESS;
event.type = HostKeyEvent::Type::KeyPressed;
else
event.type = HostKeyEvent::Type::NoEvent;
@ -547,10 +547,10 @@ void GSPanel::OnFocus( wxFocusEvent& evt )
else
DoShowMouse();
#if defined(__unix__)
#if defined(__unix__) || defined(__APPLE__)
// HACK2: In gsopen2 there is one event buffer read by both wx/gui and pad. Wx deletes
// the event before the pad see it. So you send key event directly to the pad.
HostKeyEvent event = {static_cast<HostKeyEvent::Type>(9), 0}; // X equivalent of FocusIn;
HostKeyEvent event = {HostKeyEvent::Type::FocusGained, 0};
PADWriteEvent(event);
#endif
//Console.Warning("GS frame > focus set");
@ -563,10 +563,10 @@ void GSPanel::OnFocusLost( wxFocusEvent& evt )
evt.Skip();
m_HasFocus = false;
DoShowMouse();
#if defined(__unix__)
#if defined(__unix__) || defined(__APPLE__)
// HACK2: In gsopen2 there is one event buffer read by both wx/gui and pad. Wx deletes
// the event before the pad see it. So you send key event directly to the pad.
HostKeyEvent event = {static_cast<HostKeyEvent::Type>(9), 0}; // X equivalent of FocusOut
HostKeyEvent event = {HostKeyEvent::Type::FocustLost, 0};
PADWriteEvent(event);
#endif
//Console.Warning("GS frame > focus lost");