mirror of
https://github.com/SourMesen/Mesen2.git
synced 2024-05-20 13:08:12 -04:00
Compare commits
21 commits
1f166984b5
...
64bd79a520
Author | SHA1 | Date | |
---|---|---|---|
64bd79a520 | |||
202b8f32c8 | |||
bb745910d5 | |||
238dbaca71 | |||
db6541ae76 | |||
d5bf91e51e | |||
42b163153c | |||
33373d7873 | |||
d808d3f074 | |||
5fb6025be1 | |||
0a269f2426 | |||
f4ee22bc5f | |||
c09eaaf17f | |||
6a9cd6ea58 | |||
0366f1e7af | |||
83c85fee51 | |||
98ac589229 | |||
04ce690523 | |||
116e71a484 | |||
2b3eba4261 | |||
a8aa4bf620 |
|
@ -742,6 +742,7 @@
|
|||
<ClInclude Include="Shared\Video\VideoDecoder.h" />
|
||||
<ClInclude Include="Shared\Video\VideoRenderer.h" />
|
||||
<ClInclude Include="Shared\Audio\WaveRecorder.h" />
|
||||
<ClInclude Include="Shared\Interfaces\IMouseManager.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Debugger\Base6502Assembler.cpp" />
|
||||
|
|
|
@ -1021,6 +1021,9 @@
|
|||
<ClInclude Include="Shared\Interfaces\IMessageManager.h">
|
||||
<Filter>Shared\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Shared\Interfaces\IMouseManager.h">
|
||||
<Filter>Shared\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Shared\Interfaces\INotificationListener.h">
|
||||
<Filter>Shared\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
|
|
33
Core/Shared/Interfaces/IMouseManager.h
Normal file
33
Core/Shared/Interfaces/IMouseManager.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
enum class CursorImage
|
||||
{
|
||||
Hidden,
|
||||
Arrow,
|
||||
Cross
|
||||
};
|
||||
|
||||
struct SystemMouseState
|
||||
{
|
||||
int32_t XPosition;
|
||||
int32_t YPosition;
|
||||
bool LeftButton;
|
||||
bool RightButton;
|
||||
bool MiddleButton;
|
||||
bool Button4;
|
||||
bool Button5;
|
||||
};
|
||||
|
||||
class IMouseManager
|
||||
{
|
||||
public:
|
||||
virtual ~IMouseManager() {}
|
||||
|
||||
virtual SystemMouseState GetSystemMouseState(void* rendererHandle) = 0;
|
||||
virtual bool CaptureMouse(int32_t x, int32_t y, int32_t width, int32_t height, void* rendererHandle) = 0;
|
||||
virtual void ReleaseMouse() = 0;
|
||||
virtual void SetSystemMousePosition(int32_t x, int32_t y) = 0;
|
||||
virtual void SetCursorImage(CursorImage cursor) = 0;
|
||||
virtual double GetPixelScale() = 0;
|
||||
};
|
|
@ -857,6 +857,9 @@ enum class EmulatorShortcut
|
|||
IncreaseVolume,
|
||||
DecreaseVolume,
|
||||
|
||||
PreviousTrack,
|
||||
NextTrack,
|
||||
|
||||
ToggleBgLayer1,
|
||||
ToggleBgLayer2,
|
||||
ToggleBgLayer3,
|
||||
|
|
|
@ -23,13 +23,16 @@
|
|||
#include "Windows/Renderer.h"
|
||||
#include "Windows/SoundManager.h"
|
||||
#include "Windows/WindowsKeyManager.h"
|
||||
#include "Windows/WindowsMouseManager.h"
|
||||
#elif __APPLE__
|
||||
#include "Linux/SdlSoundManager.h"
|
||||
#include "Sdl/SdlSoundManager.h"
|
||||
#include "MacOS/MacOSKeyManager.h"
|
||||
#include "MacOS/MacOSMouseManager.h"
|
||||
#else
|
||||
#include "Linux/SdlRenderer.h"
|
||||
#include "Linux/SdlSoundManager.h"
|
||||
#include "Sdl/SdlRenderer.h"
|
||||
#include "Sdl/SdlSoundManager.h"
|
||||
#include "Linux/LinuxKeyManager.h"
|
||||
#include "Linux/LinuxMouseManager.h"
|
||||
#endif
|
||||
|
||||
#include "Shared/Video/SoftwareRenderer.h"
|
||||
|
@ -37,6 +40,7 @@
|
|||
unique_ptr<IRenderingDevice> _renderer;
|
||||
unique_ptr<IAudioDevice> _soundManager;
|
||||
unique_ptr<IKeyManager> _keyManager;
|
||||
unique_ptr<IMouseManager> _mouseManager;
|
||||
unique_ptr<Emulator> _emu(new Emulator());
|
||||
bool _softwareRenderer = false;
|
||||
|
||||
|
@ -107,10 +111,13 @@ extern "C" {
|
|||
if(!noInput) {
|
||||
#ifdef _WIN32
|
||||
_keyManager.reset(new WindowsKeyManager(_emu.get(), (HWND)_windowHandle));
|
||||
_mouseManager.reset(new WindowsMouseManager());
|
||||
#elif __APPLE__
|
||||
_keyManager.reset(new MacOSKeyManager(_emu.get()));
|
||||
_mouseManager.reset(new MacOSMouseManager());
|
||||
#else
|
||||
_keyManager.reset(new LinuxKeyManager(_emu.get()));
|
||||
_mouseManager.reset(new LinuxMouseManager(_windowHandle));
|
||||
#endif
|
||||
|
||||
KeyManager::RegisterKeyManager(_keyManager.get());
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
#ifdef _WIN32
|
||||
#include "Windows/Renderer.h"
|
||||
#include "Windows/SoundManager.h"
|
||||
#include "Windows/WindowsKeyManager.h"
|
||||
#elif __APPLE__
|
||||
#include "Sdl/SdlSoundManager.h"
|
||||
#else
|
||||
#include "Linux/SdlRenderer.h"
|
||||
#include "Linux/SdlSoundManager.h"
|
||||
#include "Linux/LinuxKeyManager.h"
|
||||
#include "Sdl/SdlRenderer.h"
|
||||
#include "Sdl/SdlSoundManager.h"
|
||||
#endif
|
||||
|
||||
extern unique_ptr<Emulator> _emu;
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
#include "Core/Shared/KeyManager.h"
|
||||
#include "Core/Shared/ShortcutKeyHandler.h"
|
||||
#include "Utilities/StringUtilities.h"
|
||||
#include "Core/Shared/Interfaces/IMouseManager.h"
|
||||
|
||||
extern unique_ptr<IKeyManager> _keyManager;
|
||||
extern unique_ptr<IMouseManager> _mouseManager;
|
||||
extern unique_ptr<Emulator> _emu;
|
||||
|
||||
extern "C"
|
||||
|
@ -81,4 +83,50 @@ extern "C"
|
|||
{
|
||||
_emu->ResetLagCounter();
|
||||
}
|
||||
}
|
||||
|
||||
DllExport SystemMouseState __stdcall GetSystemMouseState(void* rendererHandle)
|
||||
{
|
||||
if(_mouseManager) {
|
||||
return _mouseManager->GetSystemMouseState(rendererHandle);
|
||||
}
|
||||
SystemMouseState state = {};
|
||||
return state;
|
||||
}
|
||||
|
||||
DllExport bool __stdcall CaptureMouse(int32_t x, int32_t y, int32_t width, int32_t height, void* rendererHandle)
|
||||
{
|
||||
if(_mouseManager) {
|
||||
return _mouseManager->CaptureMouse(x, y, width, height, rendererHandle);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DllExport void __stdcall ReleaseMouse()
|
||||
{
|
||||
if(_mouseManager) {
|
||||
_mouseManager->ReleaseMouse();
|
||||
}
|
||||
}
|
||||
|
||||
DllExport void __stdcall SetSystemMousePosition(int32_t x, int32_t y)
|
||||
{
|
||||
if(_mouseManager) {
|
||||
_mouseManager->SetSystemMousePosition(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
DllExport void __stdcall SetCursorImage(CursorImage image)
|
||||
{
|
||||
if(_mouseManager) {
|
||||
_mouseManager->SetCursorImage(image);
|
||||
}
|
||||
}
|
||||
|
||||
DllExport double __stdcall GetPixelScale()
|
||||
{
|
||||
if(_mouseManager) {
|
||||
return _mouseManager->GetPixelScale();
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,6 @@
|
|||
#include "Core/Shared/EmuSettings.h"
|
||||
#include "LinuxGameController.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
bool LinuxGameController::IsButtonPressed(int buttonNumber) { return 0; }
|
||||
int LinuxGameController::GetDeviceID() { return _deviceID; }
|
||||
bool LinuxGameController::IsDisconnected() { return _disconnected; }
|
||||
std::shared_ptr<LinuxGameController> LinuxGameController::GetController(Emulator* emu, int deviceID, bool logInformation) { return nullptr; }
|
||||
#else
|
||||
#include "libevdev/libevdev.h"
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
@ -236,4 +230,3 @@ static int print_event(struct input_event *ev)
|
|||
return 0;
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
|
115
Linux/LinuxMouseManager.cpp
Normal file
115
Linux/LinuxMouseManager.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
#include <string>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/cursorfont.h>
|
||||
|
||||
#include "LinuxMouseManager.h"
|
||||
#include "Core/Shared/MessageManager.h"
|
||||
|
||||
LinuxMouseManager::LinuxMouseManager(void* windowHandle)
|
||||
{
|
||||
_mainWindow = (Window) windowHandle;
|
||||
|
||||
_display = XOpenDisplay(nullptr);
|
||||
_defaultScreen = XDefaultScreen(_display);
|
||||
_rootWindow = XRootWindow(_display, _defaultScreen);
|
||||
|
||||
_defaultCursor = XCreateFontCursor(_display, XC_left_ptr);
|
||||
_crossCursor = XCreateFontCursor(_display, XC_crosshair);
|
||||
|
||||
XColor color = {};
|
||||
uint8_t nullCursorData = 0;
|
||||
Pixmap pixmap = XCreateBitmapFromData(_display, _rootWindow, (const char*) &nullCursorData, 1, 1);
|
||||
_hiddenCursor = XCreatePixmapCursor(_display, pixmap, pixmap, &color, &color, 0, 0);
|
||||
}
|
||||
|
||||
LinuxMouseManager::~LinuxMouseManager() {}
|
||||
|
||||
SystemMouseState LinuxMouseManager::GetSystemMouseState(void* rendererHandle)
|
||||
{
|
||||
SystemMouseState state = {};
|
||||
|
||||
Window root = 0;
|
||||
Window c = 0;
|
||||
Window child = 0;
|
||||
int rootX, rootY, childX, childY;
|
||||
uint32_t mask;
|
||||
|
||||
XGrabServer(_display);
|
||||
XQueryPointer(_display, _rootWindow, &root, &c, &rootX, &rootY, &childX, &childY, &mask);
|
||||
if(root != _rootWindow) c = root;
|
||||
while(c != 0) {
|
||||
child = c;
|
||||
XQueryPointer(_display, c, &root, &c, &rootX, &rootY, &childX, &childY, &mask);
|
||||
}
|
||||
XUngrabServer(_display);
|
||||
XFlush(_display);
|
||||
|
||||
state.XPosition = rootX;
|
||||
state.YPosition = rootY;
|
||||
state.LeftButton = (mask & (1 << 8)) != 0;
|
||||
state.RightButton = (mask & (1 << 10)) != 0;
|
||||
state.MiddleButton = (mask & (1 << 9)) != 0;
|
||||
//TODO back/forward are not supported by XQueryPointer?
|
||||
//state.Button4 = (mask & (1 << 11)) != 0;
|
||||
//state.Button5 = (mask & (1 << 12)) != 0;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
bool LinuxMouseManager::CaptureMouse(int32_t x, int32_t y, int32_t width, int32_t height, void* rendererHandle)
|
||||
{
|
||||
if(rendererHandle == nullptr) {
|
||||
//Due to the mouse position constantly being set to the center of the window and the cursor being hidden
|
||||
//actually capturing the cursor when using the software renderer is not strictly needed
|
||||
return true;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 10; i++) {
|
||||
int result = XGrabPointer(_display, (Window) rendererHandle, true, NoEventMask, GrabModeAsync, GrabModeAsync, (Window) rendererHandle, _hiddenCursor, 0);
|
||||
XFlush(_display);
|
||||
if(result == 1 && i < 9) {
|
||||
//XGrabPointer can fail with AlreadyGrabbed - this can be normal, retry a few times
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(100));
|
||||
} else {
|
||||
if(result != 0) {
|
||||
std::string message = "XGrabPointer failed: ";
|
||||
MessageManager::Log(message + std::to_string(result));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LinuxMouseManager::ReleaseMouse()
|
||||
{
|
||||
XUngrabPointer(_display, 0);
|
||||
XFlush(_display);
|
||||
}
|
||||
|
||||
void LinuxMouseManager::SetSystemMousePosition(int32_t x, int32_t y)
|
||||
{
|
||||
XWarpPointer(_display, 0, _rootWindow, 0, 0, 0, 0, x, y);
|
||||
XFlush(_display);
|
||||
}
|
||||
|
||||
void LinuxMouseManager::SetCursorImage(CursorImage cursor)
|
||||
{
|
||||
switch(cursor) {
|
||||
case CursorImage::Hidden: XDefineCursor(_display, _mainWindow, _hiddenCursor); break;
|
||||
case CursorImage::Arrow: XDefineCursor(_display, _mainWindow, _defaultCursor); break;
|
||||
case CursorImage::Cross: XDefineCursor(_display, _mainWindow, _crossCursor); break;
|
||||
}
|
||||
XFlush(_display);
|
||||
}
|
||||
|
||||
double LinuxMouseManager::GetPixelScale()
|
||||
{
|
||||
return 1.0;
|
||||
}
|
35
Linux/LinuxMouseManager.h
Normal file
35
Linux/LinuxMouseManager.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/cursorfont.h>
|
||||
|
||||
//X11 defines global macros 'Button4' and 'Button5', colliding with the fields of SystemMouseState
|
||||
//Undefine them here, as they are not needed
|
||||
#undef Button4
|
||||
#undef Button5
|
||||
|
||||
#include "Shared/Interfaces/IMouseManager.h"
|
||||
|
||||
class LinuxMouseManager : public IMouseManager
|
||||
{
|
||||
private:
|
||||
Window _mainWindow;
|
||||
|
||||
Display* _display;
|
||||
int _defaultScreen;
|
||||
Window _rootWindow;
|
||||
|
||||
Cursor _defaultCursor;
|
||||
Cursor _crossCursor;
|
||||
Cursor _hiddenCursor;
|
||||
|
||||
public:
|
||||
LinuxMouseManager(void* windowHandle);
|
||||
virtual ~LinuxMouseManager();
|
||||
|
||||
SystemMouseState GetSystemMouseState(void* rendererHandle);
|
||||
bool CaptureMouse(int32_t x, int32_t y, int32_t width, int32_t height, void* rendererHandle);
|
||||
void ReleaseMouse();
|
||||
void SetSystemMousePosition(int32_t x, int32_t y);
|
||||
void SetCursorImage(CursorImage cursor);
|
||||
double GetPixelScale();
|
||||
};
|
|
@ -1,8 +1,6 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include "Utilities/AutoResetEvent.h"
|
||||
#include "Shared/Interfaces/IKeyManager.h"
|
||||
#include "Shared/KeyDefinitions.h"
|
||||
|
||||
|
|
|
@ -27,8 +27,9 @@ MacOSKeyManager::MacOSKeyManager(Emulator* emu)
|
|||
|
||||
_disableAllKeys = false;
|
||||
|
||||
_eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:(NSEventMaskKeyDown | NSEventMaskKeyUp | NSEventMaskFlagsChanged)
|
||||
handler:^ NSEvent* (NSEvent* event) {
|
||||
NSEventMask eventMask = NSEventMaskKeyDown | NSEventMaskKeyUp | NSEventMaskFlagsChanged;
|
||||
|
||||
_eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^ NSEvent* (NSEvent* event) {
|
||||
if(_emu->GetSettings()->CheckFlag(EmulationFlags::InBackground)) {
|
||||
//Allow UI to handle key-events when main window is not in focus
|
||||
return event;
|
||||
|
|
26
MacOS/MacOSMouseManager.h
Normal file
26
MacOS/MacOSMouseManager.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
#include "Shared/Interfaces/IMouseManager.h"
|
||||
|
||||
class MacOSMouseManager : public IMouseManager
|
||||
{
|
||||
private:
|
||||
double _relativeX;
|
||||
double _relativeY;
|
||||
bool _mouseCaptured;
|
||||
bool _cursorHidden;
|
||||
|
||||
void* _eventMonitor;
|
||||
|
||||
void SetRelativeMovement(double x, double y);
|
||||
|
||||
public:
|
||||
MacOSMouseManager();
|
||||
virtual ~MacOSMouseManager();
|
||||
|
||||
SystemMouseState GetSystemMouseState(void* rendererHandle);
|
||||
bool CaptureMouse(int32_t x, int32_t y, int32_t width, int32_t height, void* rendererHandle);
|
||||
void ReleaseMouse();
|
||||
void SetSystemMousePosition(int32_t x, int32_t y);
|
||||
void SetCursorImage(CursorImage cursor);
|
||||
double GetPixelScale();
|
||||
};
|
102
MacOS/MacOSMouseManager.mm
Normal file
102
MacOS/MacOSMouseManager.mm
Normal file
|
@ -0,0 +1,102 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "MacOSMouseManager.h"
|
||||
|
||||
MacOSMouseManager::MacOSMouseManager()
|
||||
{
|
||||
_relativeX = 0.0;
|
||||
_relativeY = 0.0;
|
||||
_mouseCaptured = false;
|
||||
_cursorHidden = false;
|
||||
|
||||
NSEventMask eventMask = NSEventMaskMouseMoved | NSEventMaskLeftMouseDragged | NSEventMaskRightMouseDragged | NSEventMaskOtherMouseDragged;
|
||||
|
||||
_eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^ NSEvent* (NSEvent* event) {
|
||||
//When mouse is captured on MacOS, absolute position is frozen and only deltaX/Y gives movement data
|
||||
SetRelativeMovement([event deltaX], [event deltaY]);
|
||||
return event;
|
||||
}];
|
||||
}
|
||||
|
||||
MacOSMouseManager::~MacOSMouseManager()
|
||||
{
|
||||
[NSEvent removeMonitor:(id) _eventMonitor];
|
||||
}
|
||||
|
||||
SystemMouseState MacOSMouseManager::GetSystemMouseState(void* rendererHandle)
|
||||
{
|
||||
SystemMouseState state = {};
|
||||
if(_mouseCaptured) {
|
||||
state.XPosition = (int32_t) _relativeX;
|
||||
state.YPosition = (int32_t) _relativeY;
|
||||
} else {
|
||||
NSPoint location = [NSEvent mouseLocation];
|
||||
state.XPosition = (int32_t) location.x;
|
||||
state.YPosition = (int32_t) (CGDisplayPixelsHigh(kCGDirectMainDisplay) - location.y);
|
||||
}
|
||||
NSUInteger buttons = [NSEvent pressedMouseButtons];
|
||||
state.LeftButton = (buttons & 1) != 0;
|
||||
state.RightButton = (buttons & 2) != 0;
|
||||
state.MiddleButton = (buttons & 4) != 0;
|
||||
state.Button4 = (buttons & 8) != 0;
|
||||
state.Button5 = (buttons & 16) != 0;
|
||||
return state;
|
||||
}
|
||||
|
||||
bool MacOSMouseManager::CaptureMouse(int32_t x, int32_t y, int32_t width, int32_t height, void* rendererHandle)
|
||||
{
|
||||
NSPoint location = [NSEvent mouseLocation];
|
||||
CGAssociateMouseAndMouseCursorPosition(NO);
|
||||
_relativeX = location.x;
|
||||
_relativeY = CGDisplayPixelsHigh(kCGDirectMainDisplay) - location.y;
|
||||
_mouseCaptured = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacOSMouseManager::ReleaseMouse()
|
||||
{
|
||||
CGAssociateMouseAndMouseCursorPosition(YES);
|
||||
_mouseCaptured = false;
|
||||
}
|
||||
|
||||
void MacOSMouseManager::SetSystemMousePosition(int32_t x, int32_t y)
|
||||
{
|
||||
_relativeX = (double) x;
|
||||
_relativeY = (double) y;
|
||||
}
|
||||
|
||||
void MacOSMouseManager::SetRelativeMovement(double x, double y)
|
||||
{
|
||||
_relativeX += x;
|
||||
_relativeY += y;
|
||||
}
|
||||
|
||||
void MacOSMouseManager::SetCursorImage(CursorImage cursor)
|
||||
{
|
||||
if(cursor == CursorImage::Hidden && !_cursorHidden) {
|
||||
[NSCursor hide];
|
||||
_cursorHidden = true;
|
||||
}
|
||||
if(cursor != CursorImage::Hidden && _cursorHidden) {
|
||||
[NSCursor unhide];
|
||||
_cursorHidden = false;
|
||||
}
|
||||
switch(cursor) {
|
||||
case CursorImage::Hidden: break; //Already handled above
|
||||
case CursorImage::Arrow: [[NSCursor arrowCursor] set]; break;
|
||||
case CursorImage::Cross: [[NSCursor crosshairCursor] set]; break;
|
||||
}
|
||||
}
|
||||
|
||||
double MacOSMouseManager::GetPixelScale()
|
||||
{
|
||||
//On MacOS, Avalonia seems to have a scaling-mismatch between getting/converting points and getting element sizes
|
||||
//points seem to be given in DPI-aware pixels (as GetMouseState returns as well), but sizes in actual screen-pixels
|
||||
//The result of this function is used in the UI to correct for this with mouse-related usage
|
||||
NSScreen* screen = [NSScreen mainScreen];
|
||||
if(screen == nil) {
|
||||
return 1.0;
|
||||
}
|
||||
return [screen backingScaleFactor];
|
||||
}
|
|
@ -79,6 +79,9 @@ namespace Mesen.Config.Shortcuts
|
|||
IncreaseVolume,
|
||||
DecreaseVolume,
|
||||
|
||||
PreviousTrack,
|
||||
NextTrack,
|
||||
|
||||
ToggleBgLayer1,
|
||||
ToggleBgLayer2,
|
||||
ToggleBgLayer3,
|
||||
|
|
|
@ -2020,7 +2020,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
new RegEntry("$00.7", "Vertical scroll lock", vdp.VerticalScrollLock),
|
||||
|
||||
new RegEntry("$01.0", "Zoom sprites (2x size)", vdp.EnableDoubleSpriteSize),
|
||||
new RegEntry("$01.1", "8x16 sprites", vdp.UseLargeSprites),
|
||||
new RegEntry("$01.1", "Large sprites (8x16 or 16x16)", vdp.UseLargeSprites),
|
||||
new RegEntry("$01.3", "M3 - 240-line output", vdp.M3_Use240LineMode),
|
||||
new RegEntry("$01.4", "M1 - 224-line output", vdp.M1_Use224LineMode),
|
||||
new RegEntry("$01.5", "Vertical blank IRQ enabled", vdp.EnableVerticalBlankIrq),
|
||||
|
@ -2028,6 +2028,8 @@ namespace Mesen.Debugger.ViewModels
|
|||
new RegEntry("$01.7", "SG-1000 - 16K VRAM Mode", vdp.RenderingEnabled),
|
||||
|
||||
new RegEntry("$02", "Nametable address", vdp.NametableAddress),
|
||||
new RegEntry("$03", "Pattern table address", vdp.BgPatternTableAddress),
|
||||
new RegEntry("$04", "Color table address", vdp.ColorTableAddress),
|
||||
new RegEntry("$05", "Sprite table address", vdp.SpriteTableAddress),
|
||||
new RegEntry("$06", "Sprite tileset address", vdp.SpritePatternSelector),
|
||||
new RegEntry("$07", "Background color index", vdp.BackgroundColorIndex),
|
||||
|
|
|
@ -24,6 +24,13 @@ namespace Mesen.Interop
|
|||
|
||||
[DllImport(DllPath)][return: MarshalAs(UnmanagedType.I1)] public static extern bool HasControlDevice(ControllerType type);
|
||||
|
||||
[DllImport(DllPath)] public static extern SystemMouseState GetSystemMouseState(IntPtr rendererHandle);
|
||||
[DllImport(DllPath)][return: MarshalAs(UnmanagedType.I1)] public static extern bool CaptureMouse(Int32 x, Int32 y, Int32 width, Int32 height, IntPtr rendererHandle);
|
||||
[DllImport(DllPath)] public static extern void ReleaseMouse();
|
||||
[DllImport(DllPath)] public static extern void SetSystemMousePosition(Int32 x, Int32 y);
|
||||
[DllImport(DllPath)] public static extern void SetCursorImage(CursorImage cursor);
|
||||
[DllImport(DllPath)] public static extern double GetPixelScale();
|
||||
|
||||
[DllImport(DllPath, EntryPoint = "GetKeyName")] private static extern IntPtr GetKeyNameWrapper(UInt16 key, IntPtr outKeyName, Int32 maxLength);
|
||||
public unsafe static string GetKeyName(UInt16 key)
|
||||
{
|
||||
|
@ -51,4 +58,23 @@ namespace Mesen.Interop
|
|||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
public enum CursorImage
|
||||
{
|
||||
Hidden,
|
||||
Arrow,
|
||||
Cross
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SystemMouseState
|
||||
{
|
||||
public Int32 XPosition;
|
||||
public Int32 YPosition;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool LeftButton;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool RightButton;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool MiddleButton;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool Button4;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool Button5;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1721,6 +1721,10 @@ E
|
|||
<Value ID="ToggleAudio">Enable/Disable Audio</Value>
|
||||
<Value ID="IncreaseVolume">Increase Volume</Value>
|
||||
<Value ID="DecreaseVolume">Decrease Volume</Value>
|
||||
|
||||
<Value ID="PreviousTrack">Audio Player - Previous Track</Value>
|
||||
<Value ID="NextTrack">Audio Player - Next Track</Value>
|
||||
|
||||
<Value ID="RunSingleFrame">Run Single Frame</Value>
|
||||
|
||||
<Value ID="SetScale1x">Set Scale 1x</Value>
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Mesen.Utilities.GlobalMouseLib
|
||||
{
|
||||
public static class GlobalMouse
|
||||
{
|
||||
private static IGlobalMouseImpl _impl;
|
||||
|
||||
static GlobalMouse()
|
||||
{
|
||||
if(OperatingSystem.IsWindows()) {
|
||||
_impl = new GlobalMouseWindowsImpl();
|
||||
} else if(OperatingSystem.IsLinux()) {
|
||||
_impl = new GlobalMouseX11Impl();
|
||||
} else {
|
||||
_impl = new GlobalMouseStubImpl();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsMouseButtonPressed(MouseButtons button)
|
||||
{
|
||||
return _impl.IsMouseButtonPressed(button);
|
||||
}
|
||||
|
||||
public static MousePosition GetMousePosition(IntPtr windowFilter)
|
||||
{
|
||||
return _impl.GetMousePosition(windowFilter);
|
||||
}
|
||||
|
||||
public static void SetMousePosition(uint x, uint y)
|
||||
{
|
||||
_impl.SetMousePosition(x, y);
|
||||
}
|
||||
|
||||
public static void SetCursorIcon(CursorIcon icon)
|
||||
{
|
||||
_impl.SetCursorIcon(icon);
|
||||
}
|
||||
|
||||
public static void CaptureCursor(int x, int y, int width, int height, IntPtr rendererHandle)
|
||||
{
|
||||
_impl.CaptureCursor(x, y, width, height, rendererHandle);
|
||||
}
|
||||
|
||||
public static void ReleaseCursor()
|
||||
{
|
||||
_impl.ReleaseCursor();
|
||||
}
|
||||
}
|
||||
|
||||
public enum MouseButtons
|
||||
{
|
||||
Left = 1,
|
||||
Right = 2,
|
||||
Middle = 3,
|
||||
Button4 = 4,
|
||||
Button5 = 5
|
||||
}
|
||||
|
||||
public enum CursorIcon
|
||||
{
|
||||
Hidden,
|
||||
Arrow,
|
||||
Cross
|
||||
}
|
||||
|
||||
public struct MousePosition
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
|
||||
public MousePosition(int x, int y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Mesen.Utilities.GlobalMouseLib
|
||||
{
|
||||
public class GlobalMouseStubImpl : IGlobalMouseImpl
|
||||
{
|
||||
public MousePosition GetMousePosition(IntPtr windowFilter)
|
||||
{
|
||||
return new MousePosition(0, 0);
|
||||
}
|
||||
|
||||
public bool IsMouseButtonPressed(MouseButtons button)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetCursorIcon(CursorIcon icon)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetMousePosition(uint x, uint y)
|
||||
{
|
||||
}
|
||||
|
||||
public void CaptureCursor(int x, int y, int width, int height, IntPtr rendererHandle)
|
||||
{
|
||||
}
|
||||
|
||||
public void ReleaseCursor()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mesen.Utilities.GlobalMouseLib
|
||||
{
|
||||
public class GlobalMouseWindowsImpl : IGlobalMouseImpl
|
||||
{
|
||||
private IntPtr _arrowCursor = LoadCursor(IntPtr.Zero, new IntPtr((int)Cursor.IDC_ARROW));
|
||||
private IntPtr _crossCursor = LoadCursor(IntPtr.Zero, new IntPtr((int)Cursor.IDC_CROSS));
|
||||
|
||||
public bool IsMouseButtonPressed(MouseButtons button)
|
||||
{
|
||||
switch(button) {
|
||||
case MouseButtons.Left: return (GetAsyncKeyState((int)WindowsMouseButton.VK_LBUTTON) & 0x8000) != 0;
|
||||
case MouseButtons.Right: return (GetAsyncKeyState((int)WindowsMouseButton.VK_RBUTTON) & 0x8000) != 0;
|
||||
case MouseButtons.Middle: return (GetAsyncKeyState((int)WindowsMouseButton.VK_MBUTTON) & 0x8000) != 0;
|
||||
case MouseButtons.Button4: return (GetAsyncKeyState((int)WindowsMouseButton.VK_XBUTTON1) & 0x8000) != 0;
|
||||
case MouseButtons.Button5: return (GetAsyncKeyState((int)WindowsMouseButton.VK_XBUTTON2) & 0x8000) != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public MousePosition GetMousePosition(IntPtr windowFilter)
|
||||
{
|
||||
GetCursorPos(out CursorPoint p);
|
||||
if(windowFilter != IntPtr.Zero && WindowFromPoint(p) != windowFilter) {
|
||||
//Mouse is over another window
|
||||
return new MousePosition(-1, -1);
|
||||
}
|
||||
return new MousePosition(p.X, p.Y);
|
||||
}
|
||||
|
||||
public void SetMousePosition(uint x, uint y)
|
||||
{
|
||||
SetCursorPos(x, y);
|
||||
}
|
||||
|
||||
public void SetCursorIcon(CursorIcon icon)
|
||||
{
|
||||
switch(icon) {
|
||||
case CursorIcon.Hidden: SetCursor(IntPtr.Zero); break;
|
||||
case CursorIcon.Arrow: SetCursor(_arrowCursor); break;
|
||||
case CursorIcon.Cross: SetCursor(_crossCursor); break;
|
||||
}
|
||||
}
|
||||
|
||||
public void CaptureCursor(int x, int y, int width, int height, IntPtr rendererHandle)
|
||||
{
|
||||
ClipCursor(new WinRect() { Left = x, Top = y, Right = x + width, Bottom = y + height });
|
||||
}
|
||||
|
||||
public void ReleaseCursor()
|
||||
{
|
||||
ClipCursor(null);
|
||||
}
|
||||
|
||||
[DllImport("User32.dll")]
|
||||
private static extern short GetAsyncKeyState(int arrowKeys);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr LoadCursor(IntPtr hInstance, IntPtr lpCursorName);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr SetCursor(IntPtr hCursor);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct CursorPoint
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private class WinRect
|
||||
{
|
||||
public int Left;
|
||||
public int Top;
|
||||
public int Right;
|
||||
public int Bottom;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool GetCursorPos(out CursorPoint point);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool SetCursorPos(uint x, uint y);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool ClipCursor(WinRect? rect);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr WindowFromPoint(CursorPoint p);
|
||||
|
||||
private enum WindowsMouseButton
|
||||
{
|
||||
VK_LBUTTON = 1,
|
||||
VK_RBUTTON = 2,
|
||||
VK_MBUTTON = 4,
|
||||
VK_XBUTTON1 = 5,
|
||||
VK_XBUTTON2 = 6,
|
||||
}
|
||||
|
||||
private enum Cursor
|
||||
{
|
||||
IDC_ARROW = 32512,
|
||||
IDC_IBEAM = 32513,
|
||||
IDC_WAIT = 32514,
|
||||
IDC_CROSS = 32515,
|
||||
IDC_UPARROW = 32516,
|
||||
IDC_SIZE = 32640,
|
||||
IDC_ICON = 32641,
|
||||
IDC_SIZENWSE = 32642,
|
||||
IDC_SIZENESW = 32643,
|
||||
IDC_SIZEWE = 32644,
|
||||
IDC_SIZENS = 32645,
|
||||
IDC_SIZEALL = 32646,
|
||||
IDC_NO = 32648,
|
||||
IDC_HAND = 32649,
|
||||
IDC_APPSTARTING = 32650,
|
||||
IDC_HELP = 32651
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,334 +0,0 @@
|
|||
using Mesen.Interop;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mesen.Utilities.GlobalMouseLib;
|
||||
|
||||
public class GlobalMouseX11Impl : IGlobalMouseImpl
|
||||
{
|
||||
private X11Info _x11;
|
||||
private IntPtr _mainWindow;
|
||||
|
||||
public GlobalMouseX11Impl()
|
||||
{
|
||||
_mainWindow = ApplicationHelper.GetMainWindow()?.TryGetPlatformHandle()?.Handle ?? IntPtr.Zero;
|
||||
_x11 = new X11Info();
|
||||
}
|
||||
|
||||
public MousePosition GetMousePosition(IntPtr windowFilter)
|
||||
{
|
||||
(int x, int y) = GetCursorPos(_x11, null, out _);
|
||||
return new MousePosition(x, y);
|
||||
}
|
||||
|
||||
public bool IsMouseButtonPressed(MouseButtons button)
|
||||
{
|
||||
GetCursorPos(_x11, null, out int keys);
|
||||
switch(button) {
|
||||
case MouseButtons.Left: return (keys & (1 << 8)) != 0;
|
||||
case MouseButtons.Middle: return (keys & (1 << 9)) != 0;
|
||||
case MouseButtons.Right: return (keys & (1 << 10)) != 0;
|
||||
|
||||
//TODO back/forward are not supported by XQueryPointer?
|
||||
//case MouseButtons.Button4: return (keys & (1 << 11)) != 0;
|
||||
//case MouseButtons.Button5: return (keys & (1 << 12)) != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CaptureCursor(int x, int y, int width, int height, IntPtr rendererHandle)
|
||||
{
|
||||
for(int i = 0; i < 10; i++) {
|
||||
int result = X11Api.XGrabPointer(_x11.Display, rendererHandle, true, X11Api.EventMask.NoEventMask, X11Api.GrabMode.GrabModeAsync, X11Api.GrabMode.GrabModeAsync, rendererHandle, _x11.HiddenCursor, IntPtr.Zero);
|
||||
X11Api.XFlush(_x11.Display);
|
||||
if(result == 1 && i < 9) {
|
||||
//XGrabPointer can fail with AlreadyGrabbed - this can be normal, retry a few times
|
||||
System.Threading.Thread.Sleep(100);
|
||||
} else {
|
||||
if(result != 0) {
|
||||
EmuApi.WriteLogEntry("XGrabPointer failed: " + result.ToString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseCursor()
|
||||
{
|
||||
X11Api.XUngrabPointer(_x11.Display, IntPtr.Zero);
|
||||
X11Api.XFlush(_x11.Display);
|
||||
}
|
||||
|
||||
public void SetCursorIcon(CursorIcon icon)
|
||||
{
|
||||
X11Api.XDefineCursor(_x11.Display, _mainWindow, icon switch {
|
||||
CursorIcon.Hidden => _x11.HiddenCursor,
|
||||
CursorIcon.Cross => _x11.CrossCursor,
|
||||
CursorIcon.Arrow or _ => _x11.DefaultCursor
|
||||
});
|
||||
X11Api.XFlush(_x11.Display);
|
||||
}
|
||||
|
||||
public void SetMousePosition(uint x, uint y)
|
||||
{
|
||||
X11Api.XWarpPointer(_x11.Display, IntPtr.Zero, _x11.RootWindow, 0, 0, 0, 0, (int)x, (int)y);
|
||||
X11Api.XFlush(_x11.Display);
|
||||
}
|
||||
|
||||
public static void QueryPointer(IntPtr display, IntPtr w, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int child_x, out int child_y, out int mask)
|
||||
{
|
||||
IntPtr c;
|
||||
|
||||
X11Api.XGrabServer(display);
|
||||
|
||||
X11Api.XQueryPointer(display, w, out root, out c,
|
||||
out root_x, out root_y, out child_x, out child_y,
|
||||
out mask);
|
||||
|
||||
if(root != w)
|
||||
c = root;
|
||||
|
||||
IntPtr child_last = IntPtr.Zero;
|
||||
while(c != IntPtr.Zero) {
|
||||
child_last = c;
|
||||
X11Api.XQueryPointer(display, c, out root, out c,
|
||||
out root_x, out root_y, out child_x, out child_y,
|
||||
out mask);
|
||||
}
|
||||
X11Api.XUngrabServer(display);
|
||||
X11Api.XFlush(display);
|
||||
|
||||
child = child_last;
|
||||
}
|
||||
|
||||
public static (int x, int y) GetCursorPos(X11Info x11, IntPtr? handle, out int keys_buttons)
|
||||
{
|
||||
QueryPointer(x11.Display, handle ?? x11.RootWindow, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out keys_buttons);
|
||||
|
||||
if(handle != null) {
|
||||
return (win_x, win_y);
|
||||
} else {
|
||||
return (root_x, root_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class X11Api
|
||||
{
|
||||
const string libX11 = "libX11.so.6";
|
||||
/*const string libX11Randr = "libXrandr.so.2";
|
||||
const string libX11Ext = "libXext.so.6";
|
||||
const string libXInput = "libXi.so.6";
|
||||
const string libXCursor = "libXcursor.so.1";*/
|
||||
|
||||
[DllImport(libX11)]
|
||||
public static extern IntPtr XOpenDisplay(IntPtr display);
|
||||
|
||||
[DllImport(libX11)]
|
||||
public static extern int XDefaultScreen(IntPtr display);
|
||||
|
||||
[DllImport(libX11)]
|
||||
public static extern IntPtr XRootWindow(IntPtr display, int screen_number);
|
||||
|
||||
[DllImport(libX11)]
|
||||
public static extern bool XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child,
|
||||
out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons);
|
||||
[DllImport(libX11)]
|
||||
public static extern void XGrabServer(IntPtr display);
|
||||
[DllImport(libX11)]
|
||||
public static extern void XUngrabServer(IntPtr display);
|
||||
[DllImport(libX11)]
|
||||
public static extern int XFlush(IntPtr display);
|
||||
|
||||
[DllImport(libX11)]
|
||||
public static extern int XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask,
|
||||
GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, IntPtr timestamp);
|
||||
|
||||
[DllImport(libX11)]
|
||||
public static extern int XUngrabPointer(IntPtr display, IntPtr timestamp);
|
||||
|
||||
[DllImport(libX11)]
|
||||
public static extern IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape);
|
||||
|
||||
[DllImport(libX11)]
|
||||
public static extern int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
|
||||
|
||||
[DllImport(libX11)]
|
||||
public static extern uint XWarpPointer(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y,
|
||||
uint src_width, uint src_height, int dest_x, int dest_y);
|
||||
|
||||
[DllImport(libX11)]
|
||||
public static extern IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask,
|
||||
ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot);
|
||||
|
||||
[DllImport(libX11)]
|
||||
public static extern IntPtr XCreateBitmapFromData(IntPtr display, IntPtr drawable, byte[] data, int width, int height);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||
public struct XColor
|
||||
{
|
||||
internal IntPtr pixel;
|
||||
internal ushort red;
|
||||
internal ushort green;
|
||||
internal ushort blue;
|
||||
internal byte flags;
|
||||
internal byte pad;
|
||||
}
|
||||
|
||||
public enum GrabMode
|
||||
{
|
||||
GrabModeSync = 0,
|
||||
GrabModeAsync = 1
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum EventMask
|
||||
{
|
||||
NoEventMask = 0,
|
||||
KeyPressMask = 1 << 0,
|
||||
KeyReleaseMask = 1 << 1,
|
||||
ButtonPressMask = 1 << 2,
|
||||
ButtonReleaseMask = 1 << 3,
|
||||
EnterWindowMask = 1 << 4,
|
||||
LeaveWindowMask = 1 << 5,
|
||||
PointerMotionMask = 1 << 6,
|
||||
PointerMotionHintMask = 1 << 7,
|
||||
Button1MotionMask = 1 << 8,
|
||||
Button2MotionMask = 1 << 9,
|
||||
Button3MotionMask = 1 << 10,
|
||||
Button4MotionMask = 1 << 11,
|
||||
Button5MotionMask = 1 << 12,
|
||||
ButtonMotionMask = 1 << 13,
|
||||
KeymapStateMask = 1 << 14,
|
||||
ExposureMask = 1 << 15,
|
||||
VisibilityChangeMask = 1 << 16,
|
||||
StructureNotifyMask = 1 << 17,
|
||||
ResizeRedirectMask = 1 << 18,
|
||||
SubstructureNotifyMask = 1 << 19,
|
||||
SubstructureRedirectMask = 1 << 20,
|
||||
FocusChangeMask = 1 << 21,
|
||||
PropertyChangeMask = 1 << 22,
|
||||
ColormapChangeMask = 1 << 23,
|
||||
OwnerGrabButtonMask = 1 << 24
|
||||
}
|
||||
|
||||
public enum CursorFontShape
|
||||
{
|
||||
XC_X_cursor = 0,
|
||||
XC_arrow = 2,
|
||||
XC_based_arrow_down = 4,
|
||||
XC_based_arrow_up = 6,
|
||||
XC_boat = 8,
|
||||
XC_bogosity = 10,
|
||||
XC_bottom_left_corner = 12,
|
||||
XC_bottom_right_corner = 14,
|
||||
XC_bottom_side = 16,
|
||||
XC_bottom_tee = 18,
|
||||
XC_box_spiral = 20,
|
||||
XC_center_ptr = 22,
|
||||
|
||||
XC_circle = 24,
|
||||
XC_clock = 26,
|
||||
XC_coffee_mug = 28,
|
||||
XC_cross = 30,
|
||||
XC_cross_reverse = 32,
|
||||
XC_crosshair = 34,
|
||||
XC_diamond_cross = 36,
|
||||
XC_dot = 38,
|
||||
XC_dotbox = 40,
|
||||
XC_double_arrow = 42,
|
||||
XC_draft_large = 44,
|
||||
XC_draft_small = 46,
|
||||
|
||||
XC_draped_box = 48,
|
||||
XC_exchange = 50,
|
||||
XC_fleur = 52,
|
||||
XC_gobbler = 54,
|
||||
XC_gumby = 56,
|
||||
XC_hand1 = 58,
|
||||
XC_hand2 = 60,
|
||||
XC_heart = 62,
|
||||
XC_icon = 64,
|
||||
XC_iron_cross = 66,
|
||||
XC_left_ptr = 68,
|
||||
XC_left_side = 70,
|
||||
|
||||
XC_left_tee = 72,
|
||||
XC_left_button = 74,
|
||||
XC_ll_angle = 76,
|
||||
XC_lr_angle = 78,
|
||||
XC_man = 80,
|
||||
XC_middlebutton = 82,
|
||||
XC_mouse = 84,
|
||||
XC_pencil = 86,
|
||||
XC_pirate = 88,
|
||||
XC_plus = 90,
|
||||
XC_question_arrow = 92,
|
||||
XC_right_ptr = 94,
|
||||
|
||||
XC_right_side = 96,
|
||||
XC_right_tee = 98,
|
||||
XC_rightbutton = 100,
|
||||
XC_rtl_logo = 102,
|
||||
XC_sailboat = 104,
|
||||
XC_sb_down_arrow = 106,
|
||||
XC_sb_h_double_arrow = 108,
|
||||
XC_sb_left_arrow = 110,
|
||||
XC_sb_right_arrow = 112,
|
||||
XC_sb_up_arrow = 114,
|
||||
XC_sb_v_double_arrow = 116,
|
||||
XC_sb_shuttle = 118,
|
||||
|
||||
XC_sizing = 120,
|
||||
XC_spider = 122,
|
||||
XC_spraycan = 124,
|
||||
XC_star = 126,
|
||||
XC_target = 128,
|
||||
XC_tcross = 130,
|
||||
XC_top_left_arrow = 132,
|
||||
XC_top_left_corner = 134,
|
||||
XC_top_right_corner = 136,
|
||||
XC_top_side = 138,
|
||||
XC_top_tee = 140,
|
||||
XC_trek = 142,
|
||||
|
||||
XC_ul_angle = 144,
|
||||
XC_umbrella = 146,
|
||||
XC_ur_angle = 148,
|
||||
XC_watch = 150,
|
||||
XC_xterm = 152,
|
||||
XC_num_glyphs = 154
|
||||
}
|
||||
}
|
||||
|
||||
public class X11Info
|
||||
{
|
||||
public IntPtr Display { get; }
|
||||
public int DefaultScreen { get; }
|
||||
public IntPtr RootWindow { get; }
|
||||
|
||||
public IntPtr DefaultCursor { get; }
|
||||
public IntPtr CrossCursor { get; }
|
||||
public IntPtr HiddenCursor { get; }
|
||||
|
||||
private static readonly byte[] NullCursorData = new byte[] { 0 };
|
||||
|
||||
public X11Info()
|
||||
{
|
||||
Display = X11Api.XOpenDisplay(IntPtr.Zero);
|
||||
DefaultScreen = X11Api.XDefaultScreen(Display);
|
||||
RootWindow = X11Api.XRootWindow(Display, DefaultScreen);
|
||||
|
||||
DefaultCursor = X11Api.XCreateFontCursor(Display, X11Api.CursorFontShape.XC_left_ptr);
|
||||
CrossCursor = X11Api.XCreateFontCursor(Display, X11Api.CursorFontShape.XC_crosshair);
|
||||
HiddenCursor = GetNullCursor(Display);
|
||||
}
|
||||
|
||||
private IntPtr GetNullCursor(IntPtr display)
|
||||
{
|
||||
X11Api.XColor color = new X11Api.XColor();
|
||||
IntPtr pixmap = X11Api.XCreateBitmapFromData(display, RootWindow, NullCursorData, 1, 1);
|
||||
return X11Api.XCreatePixmapCursor(display, pixmap, pixmap, ref color, ref color, 0, 0);
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Mesen.Utilities.GlobalMouseLib
|
||||
{
|
||||
public interface IGlobalMouseImpl
|
||||
{
|
||||
MousePosition GetMousePosition(IntPtr windowFilter);
|
||||
bool IsMouseButtonPressed(MouseButtons button);
|
||||
void SetCursorIcon(CursorIcon icon);
|
||||
void SetMousePosition(uint x, uint y);
|
||||
void CaptureCursor(int x, int y, int width, int height, IntPtr rendererHandle);
|
||||
void ReleaseCursor();
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ using Avalonia.Threading;
|
|||
using Mesen.Config;
|
||||
using Mesen.Interop;
|
||||
using Mesen.Localization;
|
||||
using Mesen.Utilities.GlobalMouseLib;
|
||||
using Mesen.ViewModels;
|
||||
using Mesen.Views;
|
||||
using Mesen.Windows;
|
||||
|
@ -27,19 +26,22 @@ namespace Mesen.Utilities
|
|||
|
||||
private DispatcherTimer _timer = new DispatcherTimer();
|
||||
|
||||
private NativeRenderer _renderer;
|
||||
private Control _renderer;
|
||||
private bool _usesSoftwareRenderer;
|
||||
private MainMenuView _mainMenu;
|
||||
private MainWindow _wnd;
|
||||
|
||||
private MousePosition _prevPosition;
|
||||
private int _prevPositionX;
|
||||
private int _prevPositionY;
|
||||
private bool _mouseCaptured = false;
|
||||
private DateTime _lastMouseMove = DateTime.Now;
|
||||
|
||||
public MouseManager(MainWindow wnd, NativeRenderer renderer, MainMenuView mainMenu)
|
||||
public MouseManager(MainWindow wnd, Control renderer, MainMenuView mainMenu, bool usesSoftwareRenderer)
|
||||
{
|
||||
_wnd = wnd;
|
||||
_renderer = renderer;
|
||||
_mainMenu = mainMenu;
|
||||
_usesSoftwareRenderer = usesSoftwareRenderer;
|
||||
|
||||
_timer.Interval = TimeSpan.FromMilliseconds(15);
|
||||
_timer.Tick += tmrProcessMouse;
|
||||
|
@ -58,9 +60,10 @@ namespace Mesen.Utilities
|
|||
if(MainWindowViewModel.Instance.RecentGames.Visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
SystemMouseState mouseState = InputApi.GetSystemMouseState(GetRendererHandle());
|
||||
|
||||
bool leftPressed = GlobalMouse.IsMouseButtonPressed(MouseButtons.Left);
|
||||
if(_wnd.IsActive && leftPressed && !IsPointerInMenu() && (EmuApi.IsRunning() || !MainWindowViewModel.Instance.RecentGames.Visible)) {
|
||||
if(_wnd.IsActive && mouseState.LeftButton && !IsPointerInMenu() && (EmuApi.IsRunning() || !MainWindowViewModel.Instance.RecentGames.Visible)) {
|
||||
//Close menu when renderer is clicked
|
||||
_mainMenu.MainMenu.Close();
|
||||
if(MainWindowViewModel.Instance.AudioPlayer == null) {
|
||||
|
@ -71,45 +74,41 @@ namespace Mesen.Utilities
|
|||
}
|
||||
|
||||
PixelPoint rendererTopLeft = _renderer.PointToScreen(new Point());
|
||||
PixelRect rendererScreenRect = new PixelRect(rendererTopLeft, PixelSize.FromSize(_renderer.Bounds.Size, LayoutHelper.GetLayoutScale(_wnd)));
|
||||
PixelRect rendererScreenRect = new PixelRect(rendererTopLeft, PixelSize.FromSize(_renderer.Bounds.Size, LayoutHelper.GetLayoutScale(_wnd) / InputApi.GetPixelScale()));
|
||||
|
||||
MousePosition p = GlobalMouse.GetMousePosition(_renderer.Handle);
|
||||
if(_prevPosition.X != p.X || _prevPosition.Y != p.Y) {
|
||||
if(_prevPositionX != mouseState.XPosition || _prevPositionY != mouseState.YPosition) {
|
||||
//Send mouse movement x/y values to core
|
||||
if(_mouseCaptured) {
|
||||
InputApi.SetMouseMovement((Int16)(p.X - _prevPosition.X), (Int16)(p.Y - _prevPosition.Y));
|
||||
InputApi.SetMouseMovement((Int16)(mouseState.XPosition - _prevPositionX), (Int16)(mouseState.YPosition - _prevPositionY));
|
||||
}
|
||||
_prevPosition = p;
|
||||
_prevPositionX = mouseState.XPosition;
|
||||
_prevPositionY = mouseState.YPosition;
|
||||
_lastMouseMove = DateTime.Now;
|
||||
}
|
||||
PixelPoint mousePos = new PixelPoint(p.X, p.Y);
|
||||
PixelPoint mousePos = new PixelPoint(mouseState.XPosition, mouseState.YPosition);
|
||||
|
||||
if(_wnd.IsActive && (_mainMenu.IsPointerOver || _mainMenu.IsKeyboardFocusWithin || _mainMenu.MainMenu.IsOpen)) {
|
||||
//When mouse or keyboard focus is in menu, release mouse and keep arrow cursor
|
||||
SetMouseOffScreen();
|
||||
ReleaseMouse();
|
||||
if(rendererScreenRect.Contains(mousePos)) {
|
||||
GlobalMouse.SetCursorIcon(CursorIcon.Arrow);
|
||||
InputApi.SetCursorImage(CursorImage.Arrow);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(rendererScreenRect.Contains(mousePos)) {
|
||||
//Send mouse state to emulation core
|
||||
Point rendererPos = _renderer.PointToClient(mousePos) * LayoutHelper.GetLayoutScale(_wnd);
|
||||
Point rendererPos = _renderer.PointToClient(mousePos) * LayoutHelper.GetLayoutScale(_wnd) / InputApi.GetPixelScale();
|
||||
InputApi.SetMousePosition(rendererPos.X / rendererScreenRect.Width, rendererPos.Y / rendererScreenRect.Height);
|
||||
|
||||
bool rightPressed = GlobalMouse.IsMouseButtonPressed(MouseButtons.Right);
|
||||
bool middlePressed = GlobalMouse.IsMouseButtonPressed(MouseButtons.Middle);
|
||||
bool button4Pressed = GlobalMouse.IsMouseButtonPressed(MouseButtons.Button4);
|
||||
bool button5Pressed = GlobalMouse.IsMouseButtonPressed(MouseButtons.Button5);
|
||||
bool buttonPressed = (leftPressed || rightPressed || middlePressed || button4Pressed || button5Pressed);
|
||||
bool buttonPressed = (mouseState.LeftButton || mouseState.RightButton || mouseState.MiddleButton || mouseState.Button4 || mouseState.Button5);
|
||||
|
||||
InputApi.SetKeyState(LeftMouseButtonKeyCode, leftPressed);
|
||||
InputApi.SetKeyState(RightMouseButtonKeyCode, rightPressed);
|
||||
InputApi.SetKeyState(MiddleMouseButtonKeyCode, middlePressed);
|
||||
InputApi.SetKeyState(MouseButton4KeyCode, button4Pressed);
|
||||
InputApi.SetKeyState(MouseButton5KeyCode, button5Pressed);
|
||||
InputApi.SetKeyState(LeftMouseButtonKeyCode, mouseState.LeftButton);
|
||||
InputApi.SetKeyState(RightMouseButtonKeyCode, mouseState.RightButton);
|
||||
InputApi.SetKeyState(MiddleMouseButtonKeyCode, mouseState.MiddleButton);
|
||||
InputApi.SetKeyState(MouseButton4KeyCode, mouseState.Button4);
|
||||
InputApi.SetKeyState(MouseButton5KeyCode, mouseState.Button5);
|
||||
|
||||
if(!_mouseCaptured && AllowMouseCapture && buttonPressed) {
|
||||
//If the mouse button is clicked and mouse isn't captured but can be, turn on mouse capture
|
||||
|
@ -118,16 +117,18 @@ namespace Mesen.Utilities
|
|||
|
||||
if(_mouseCaptured) {
|
||||
if(AllowMouseCapture) {
|
||||
GlobalMouse.SetCursorIcon(CursorIcon.Hidden);
|
||||
GlobalMouse.SetMousePosition((uint)(rendererTopLeft.X + rendererScreenRect.Width / 2), (uint)(rendererTopLeft.Y + rendererScreenRect.Height / 2));
|
||||
_prevPosition = GlobalMouse.GetMousePosition(_renderer.Handle);
|
||||
InputApi.SetCursorImage(CursorImage.Hidden);
|
||||
InputApi.SetSystemMousePosition(rendererTopLeft.X + rendererScreenRect.Width / 2, rendererTopLeft.Y + rendererScreenRect.Height / 2);
|
||||
SystemMouseState newState = InputApi.GetSystemMouseState(GetRendererHandle());
|
||||
_prevPositionX = newState.XPosition;
|
||||
_prevPositionY = newState.YPosition;
|
||||
} else {
|
||||
ReleaseMouse();
|
||||
}
|
||||
}
|
||||
|
||||
if(!_mouseCaptured) {
|
||||
GlobalMouse.SetCursorIcon(MouseIcon);
|
||||
InputApi.SetCursorImage(MouseIcon);
|
||||
}
|
||||
} else {
|
||||
SetMouseOffScreen();
|
||||
|
@ -137,8 +138,8 @@ namespace Mesen.Utilities
|
|||
private void UpdateMainMenuVisibility()
|
||||
{
|
||||
//Get global mouse position without restrictions - need to know if mouse is over menu or not
|
||||
MousePosition p = GlobalMouse.GetMousePosition(IntPtr.Zero);
|
||||
PixelPoint mousePos = new PixelPoint(p.X, p.Y);
|
||||
SystemMouseState mouseState = InputApi.GetSystemMouseState(IntPtr.Zero);
|
||||
PixelPoint mousePos = new PixelPoint(mouseState.XPosition, mouseState.YPosition);
|
||||
|
||||
bool inExclusiveFullscreen = _wnd.WindowState == WindowState.FullScreen && ConfigManager.Config.Video.UseExclusiveFullscreen;
|
||||
bool autoHideMenu = _wnd.WindowState == WindowState.FullScreen || ConfigManager.Config.Preferences.AutoHideMenu;
|
||||
|
@ -196,12 +197,12 @@ namespace Mesen.Utilities
|
|||
}
|
||||
}
|
||||
|
||||
private CursorIcon MouseIcon
|
||||
private CursorImage MouseIcon
|
||||
{
|
||||
get
|
||||
{
|
||||
if(!EmuApi.IsRunning() || EmuApi.IsPaused()) {
|
||||
return CursorIcon.Arrow;
|
||||
return CursorImage.Arrow;
|
||||
}
|
||||
|
||||
bool hasLightGun = (
|
||||
|
@ -214,18 +215,18 @@ namespace Mesen.Utilities
|
|||
|
||||
if(hasLightGun) {
|
||||
if(ConfigManager.Config.Input.HidePointerForLightGuns) {
|
||||
return CursorIcon.Hidden;
|
||||
return CursorImage.Hidden;
|
||||
} else {
|
||||
return CursorIcon.Cross;
|
||||
return CursorImage.Cross;
|
||||
}
|
||||
} else if(InputApi.HasControlDevice(ControllerType.OekaKidsTablet)) {
|
||||
return CursorIcon.Cross;
|
||||
return CursorImage.Cross;
|
||||
}
|
||||
|
||||
if((DateTime.Now - _lastMouseMove).TotalSeconds > 1) {
|
||||
return CursorIcon.Hidden;
|
||||
return CursorImage.Hidden;
|
||||
} else {
|
||||
return CursorIcon.Arrow;
|
||||
return CursorImage.Arrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -233,13 +234,13 @@ namespace Mesen.Utilities
|
|||
private void CaptureMouse()
|
||||
{
|
||||
if(!_mouseCaptured && AllowMouseCapture) {
|
||||
DisplayMessageHelper.DisplayMessage("Input", ResourceHelper.GetMessage("MouseModeEnabled"));
|
||||
_mouseCaptured = true;
|
||||
|
||||
PixelPoint topLeft = _renderer.PointToScreen(new Point());
|
||||
PixelRect rendererScreenRect = new PixelRect(topLeft, PixelSize.FromSize(_renderer.Bounds.Size, LayoutHelper.GetLayoutScale(_wnd)));
|
||||
|
||||
GlobalMouse.CaptureCursor(topLeft.X, topLeft.Y, rendererScreenRect.Width, rendererScreenRect.Height, _renderer.Handle);
|
||||
if(InputApi.CaptureMouse(topLeft.X, topLeft.Y, rendererScreenRect.Width, rendererScreenRect.Height, GetRendererHandle())) {
|
||||
DisplayMessageHelper.DisplayMessage("Input", ResourceHelper.GetMessage("MouseModeEnabled"));
|
||||
_mouseCaptured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,10 +248,15 @@ namespace Mesen.Utilities
|
|||
{
|
||||
if(_mouseCaptured) {
|
||||
_mouseCaptured = false;
|
||||
GlobalMouse.ReleaseCursor();
|
||||
InputApi.ReleaseMouse();
|
||||
}
|
||||
}
|
||||
|
||||
private IntPtr GetRendererHandle()
|
||||
{
|
||||
return _usesSoftwareRenderer ? IntPtr.Zero : (_renderer as NativeRenderer)!.Handle;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if(_timer is DispatcherTimer timer) {
|
||||
|
|
|
@ -46,6 +46,9 @@ namespace Mesen.Utilities
|
|||
case EmulatorShortcut.IncreaseVolume: IncreaseVolume(); break;
|
||||
case EmulatorShortcut.DecreaseVolume: DecreaseVolume(); break;
|
||||
|
||||
case EmulatorShortcut.PreviousTrack: GoToPreviousTrack(); break;
|
||||
case EmulatorShortcut.NextTrack: GoToNextTrack(); break;
|
||||
|
||||
case EmulatorShortcut.ToggleFps: ToggleFps(); break;
|
||||
case EmulatorShortcut.ToggleGameTimer: ToggleGameTimer(); break;
|
||||
case EmulatorShortcut.ToggleFrameCounter: ToggleFrameCounter(); break;
|
||||
|
@ -436,14 +439,38 @@ namespace Mesen.Utilities
|
|||
|
||||
private void IncreaseVolume()
|
||||
{
|
||||
ConfigManager.Config.Audio.MasterVolume = (uint)Math.Min(100, (int)ConfigManager.Config.Audio.MasterVolume + 5);
|
||||
ConfigManager.Config.Audio.ApplyConfig();
|
||||
if(MainWindowModel.AudioPlayer == null) {
|
||||
ConfigManager.Config.Audio.MasterVolume = (uint)Math.Min(100, (int)ConfigManager.Config.Audio.MasterVolume + 5);
|
||||
ConfigManager.Config.Audio.ApplyConfig();
|
||||
} else {
|
||||
ConfigManager.Config.AudioPlayer.Volume = (uint)Math.Min(100, (int)ConfigManager.Config.AudioPlayer.Volume + 5);
|
||||
ConfigManager.Config.AudioPlayer.ApplyConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private void DecreaseVolume()
|
||||
{
|
||||
ConfigManager.Config.Audio.MasterVolume = (uint)Math.Max(0, (int)ConfigManager.Config.Audio.MasterVolume - 5);
|
||||
ConfigManager.Config.Audio.ApplyConfig();
|
||||
if(MainWindowModel.AudioPlayer == null) {
|
||||
ConfigManager.Config.Audio.MasterVolume = (uint)Math.Max(0, (int)ConfigManager.Config.Audio.MasterVolume - 5);
|
||||
ConfigManager.Config.Audio.ApplyConfig();
|
||||
} else {
|
||||
ConfigManager.Config.AudioPlayer.Volume = (uint)Math.Max(0, (int)ConfigManager.Config.AudioPlayer.Volume - 5);
|
||||
ConfigManager.Config.AudioPlayer.ApplyConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private void GoToPreviousTrack()
|
||||
{
|
||||
if(MainWindowModel.AudioPlayer != null) {
|
||||
EmuApi.ProcessAudioPlayerAction(new AudioPlayerActionParams() { Action = AudioPlayerAction.PrevTrack });
|
||||
}
|
||||
}
|
||||
|
||||
private void GoToNextTrack()
|
||||
{
|
||||
if(MainWindowModel.AudioPlayer != null) {
|
||||
EmuApi.ProcessAudioPlayerAction(new AudioPlayerActionParams() { Action = AudioPlayerAction.NextTrack });
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleFrameCounter()
|
||||
|
|
|
@ -83,6 +83,9 @@ namespace Mesen.ViewModels
|
|||
EmulatorShortcut.IncreaseVolume,
|
||||
EmulatorShortcut.DecreaseVolume,
|
||||
|
||||
EmulatorShortcut.PreviousTrack,
|
||||
EmulatorShortcut.NextTrack,
|
||||
|
||||
EmulatorShortcut.MaxSpeed,
|
||||
EmulatorShortcut.IncreaseSpeed,
|
||||
EmulatorShortcut.DecreaseSpeed,
|
||||
|
|
|
@ -11,7 +11,6 @@ using Mesen.Interop;
|
|||
using Avalonia.Threading;
|
||||
using Avalonia;
|
||||
using Mesen.Config;
|
||||
using Mesen.Utilities.GlobalMouseLib;
|
||||
using Mesen.Utilities;
|
||||
using Mesen.Localization;
|
||||
using Avalonia.Remote.Protocol.Input;
|
||||
|
@ -116,15 +115,15 @@ namespace Mesen.Windows
|
|||
private void UpdateKeyDisplay()
|
||||
{
|
||||
if(!_allowKeyboardOnly) {
|
||||
MousePosition p = GlobalMouse.GetMousePosition(IntPtr.Zero);
|
||||
PixelPoint mousePos = new PixelPoint(p.X, p.Y);
|
||||
PixelRect clientBounds = new PixelRect(this.PointToScreen(new Point(0, 0)), PixelSize.FromSize(Bounds.Size, LayoutHelper.GetLayoutScale(this)));
|
||||
SystemMouseState mouseState = InputApi.GetSystemMouseState(IntPtr.Zero);
|
||||
PixelPoint mousePos = new PixelPoint(mouseState.XPosition, mouseState.YPosition);
|
||||
PixelRect clientBounds = new PixelRect(this.PointToScreen(new Point(0, 0)), PixelSize.FromSize(Bounds.Size, LayoutHelper.GetLayoutScale(this) / InputApi.GetPixelScale()));
|
||||
bool mouseInsideWindow = clientBounds.Contains(mousePos);
|
||||
InputApi.SetKeyState(MouseManager.LeftMouseButtonKeyCode, mouseInsideWindow && GlobalMouse.IsMouseButtonPressed(MouseButtons.Left));
|
||||
InputApi.SetKeyState(MouseManager.RightMouseButtonKeyCode, mouseInsideWindow && GlobalMouse.IsMouseButtonPressed(MouseButtons.Right));
|
||||
InputApi.SetKeyState(MouseManager.MiddleMouseButtonKeyCode, mouseInsideWindow && GlobalMouse.IsMouseButtonPressed(MouseButtons.Middle));
|
||||
InputApi.SetKeyState(MouseManager.MouseButton4KeyCode, mouseInsideWindow && GlobalMouse.IsMouseButtonPressed(MouseButtons.Button4));
|
||||
InputApi.SetKeyState(MouseManager.MouseButton5KeyCode, mouseInsideWindow && GlobalMouse.IsMouseButtonPressed(MouseButtons.Button5));
|
||||
InputApi.SetKeyState(MouseManager.LeftMouseButtonKeyCode, mouseInsideWindow && mouseState.LeftButton);
|
||||
InputApi.SetKeyState(MouseManager.RightMouseButtonKeyCode, mouseInsideWindow && mouseState.RightButton);
|
||||
InputApi.SetKeyState(MouseManager.MiddleMouseButtonKeyCode, mouseInsideWindow && mouseState.MiddleButton);
|
||||
InputApi.SetKeyState(MouseManager.MouseButton4KeyCode, mouseInsideWindow && mouseState.Button4);
|
||||
InputApi.SetKeyState(MouseManager.MouseButton5KeyCode, mouseInsideWindow && mouseState.Button5);
|
||||
|
||||
List<UInt16> scanCodes = InputApi.GetPressedKeys();
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ using Avalonia.Data;
|
|||
using Mesen.Interop;
|
||||
using Mesen.ViewModels;
|
||||
using Avalonia.Layout;
|
||||
using Mesen.Utilities.GlobalMouseLib;
|
||||
using Mesen.Utilities;
|
||||
using Mesen.Config;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -72,15 +71,23 @@ namespace Mesen.Windows
|
|||
return;
|
||||
}
|
||||
|
||||
bool leftPressed = GlobalMouse.IsMouseButtonPressed(MouseButtons.Left);
|
||||
MousePosition p = GlobalMouse.GetMousePosition(_renderer.Handle);
|
||||
PixelPoint mousePos = new PixelPoint(p.X, p.Y);
|
||||
PixelPoint rendererTopLeft = _renderer.PointToScreen(new Point());
|
||||
PixelRect rendererScreenRect = new PixelRect(rendererTopLeft, PixelSize.FromSize(_renderer.Bounds.Size, LayoutHelper.GetLayoutScale(this)));
|
||||
bool usesSoftwareRenderer = _model.IsSoftwareRendererVisible;
|
||||
|
||||
SystemMouseState mouseState = InputApi.GetSystemMouseState(usesSoftwareRenderer ? IntPtr.Zero : _renderer.Handle);
|
||||
PixelPoint mousePos = new PixelPoint(mouseState.XPosition, mouseState.YPosition);
|
||||
|
||||
PixelPoint rendererTopLeft;
|
||||
PixelRect rendererScreenRect;
|
||||
if(usesSoftwareRenderer) {
|
||||
rendererTopLeft = _softwareRenderer.PointToScreen(new Point());
|
||||
rendererScreenRect = new PixelRect(rendererTopLeft, PixelSize.FromSize(_softwareRenderer.Bounds.Size, LayoutHelper.GetLayoutScale(this) / InputApi.GetPixelScale()));
|
||||
} else {
|
||||
rendererTopLeft = _renderer.PointToScreen(new Point());
|
||||
rendererScreenRect = new PixelRect(rendererTopLeft, PixelSize.FromSize(_renderer.Bounds.Size, LayoutHelper.GetLayoutScale(this) / InputApi.GetPixelScale()));
|
||||
}
|
||||
|
||||
if(rendererScreenRect.Contains(mousePos)) {
|
||||
GlobalMouse.SetCursorIcon(CursorIcon.Arrow);
|
||||
if(leftPressed && !_prevLeftPressed) {
|
||||
if(mouseState.LeftButton && !_prevLeftPressed) {
|
||||
if(_mainMenu.IsOpen) {
|
||||
_mainMenu.Close();
|
||||
} else {
|
||||
|
@ -89,7 +96,7 @@ namespace Mesen.Windows
|
|||
}
|
||||
}
|
||||
|
||||
_prevLeftPressed = leftPressed;
|
||||
_prevLeftPressed = mouseState.LeftButton;
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace Mesen.Windows
|
|||
private NativeRenderer _renderer;
|
||||
private SoftwareRendererView _softwareRenderer;
|
||||
private Size _rendererSize;
|
||||
private bool _usesSoftwareRenderer;
|
||||
|
||||
private Size _originalSize;
|
||||
private PixelPoint _originalPos;
|
||||
|
@ -67,6 +68,7 @@ namespace Mesen.Windows
|
|||
{
|
||||
_testModeEnabled = System.Diagnostics.Debugger.IsAttached;
|
||||
_isLinux = OperatingSystem.IsLinux();
|
||||
_usesSoftwareRenderer = ConfigManager.Config.Video.UseSoftwareRenderer || OperatingSystem.IsMacOS();
|
||||
|
||||
_model = new MainWindowViewModel();
|
||||
DataContext = _model;
|
||||
|
@ -94,7 +96,7 @@ namespace Mesen.Windows
|
|||
_softwareRenderer = this.GetControl<SoftwareRendererView>("SoftwareRenderer");
|
||||
_audioPlayer = this.GetControl<ContentControl>("AudioPlayer");
|
||||
_mainMenu = this.GetControl<MainMenuView>("MainMenu");
|
||||
_mouseManager = new MouseManager(this, _renderer, _mainMenu);
|
||||
_mouseManager = new MouseManager(this, _usesSoftwareRenderer ? _softwareRenderer : _renderer, _mainMenu, _usesSoftwareRenderer);
|
||||
ConfigManager.Config.MainWindow.LoadWindowSettings(this);
|
||||
|
||||
#if DEBUG
|
||||
|
@ -214,7 +216,7 @@ namespace Mesen.Windows
|
|||
ConfigManager.HomeFolder,
|
||||
TryGetPlatformHandle()?.Handle ?? IntPtr.Zero,
|
||||
_renderer.Handle,
|
||||
ConfigManager.Config.Video.UseSoftwareRenderer || OperatingSystem.IsMacOS(),
|
||||
_usesSoftwareRenderer,
|
||||
cmdLine.NoAudio,
|
||||
cmdLine.NoVideo,
|
||||
cmdLine.NoInput
|
||||
|
|
|
@ -182,6 +182,7 @@
|
|||
<ClInclude Include="WindowsKeyManager.h" />
|
||||
<ClInclude Include="Renderer.h" />
|
||||
<ClInclude Include="SoundManager.h" />
|
||||
<ClInclude Include="WindowsMouseManager.h" />
|
||||
<ClInclude Include="Common.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -196,6 +197,7 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="Renderer.cpp" />
|
||||
<ClCompile Include="SoundManager.cpp" />
|
||||
<ClCompile Include="WindowsMouseManager.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="DirectXTK\SpriteEffect_SpritePixelShader.inc" />
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
<ClInclude Include="WindowsKeyManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WindowsMouseManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="XInputManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -70,6 +73,9 @@
|
|||
<ClCompile Include="WindowsKeyManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WindowsMouseManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="XInputManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
71
Windows/WindowsMouseManager.cpp
Normal file
71
Windows/WindowsMouseManager.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
#include "Common.h"
|
||||
#include "WindowsMouseManager.h"
|
||||
|
||||
WindowsMouseManager::WindowsMouseManager()
|
||||
{
|
||||
_arrowCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
_crossCursor = LoadCursor(nullptr, IDC_CROSS);
|
||||
}
|
||||
|
||||
WindowsMouseManager::~WindowsMouseManager() {}
|
||||
|
||||
SystemMouseState WindowsMouseManager::GetSystemMouseState(void* rendererHandle)
|
||||
{
|
||||
SystemMouseState state = {};
|
||||
POINT point;
|
||||
GetCursorPos(&point);
|
||||
if(rendererHandle != nullptr && WindowFromPoint(point) != (HWND) rendererHandle) {
|
||||
//Mouse is over another window
|
||||
state.XPosition = -1;
|
||||
state.YPosition = -1;
|
||||
} else {
|
||||
state.XPosition = point.x;
|
||||
state.YPosition = point.y;
|
||||
}
|
||||
state.LeftButton = (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0;
|
||||
state.RightButton = (GetAsyncKeyState(VK_RBUTTON) & 0x8000) != 0;
|
||||
state.MiddleButton = (GetAsyncKeyState(VK_MBUTTON) & 0x8000) != 0;
|
||||
state.Button4 = (GetAsyncKeyState(VK_XBUTTON1) & 0x8000) != 0;
|
||||
state.Button5 = (GetAsyncKeyState(VK_XBUTTON2) & 0x8000) != 0;
|
||||
return state;
|
||||
}
|
||||
|
||||
bool WindowsMouseManager::CaptureMouse(int32_t x, int32_t y, int32_t width, int32_t height, void* rendererHandle)
|
||||
{
|
||||
if(rendererHandle == nullptr) {
|
||||
//TODO Attempting to capture the cursor when using the sofware renderer behaves really erratically
|
||||
//cursor is not actually locked but clicks outside the window do nothing, and movement is really odd (not usable)
|
||||
return false;
|
||||
}
|
||||
RECT rect;
|
||||
rect.left = x;
|
||||
rect.top = y;
|
||||
rect.right = x + width;
|
||||
rect.bottom = y + height;
|
||||
ClipCursor(&rect);
|
||||
return true;
|
||||
}
|
||||
|
||||
void WindowsMouseManager::ReleaseMouse()
|
||||
{
|
||||
ClipCursor(nullptr);
|
||||
}
|
||||
|
||||
void WindowsMouseManager::SetSystemMousePosition(int32_t x, int32_t y)
|
||||
{
|
||||
SetCursorPos(x, y);
|
||||
}
|
||||
|
||||
void WindowsMouseManager::SetCursorImage(CursorImage cursor)
|
||||
{
|
||||
switch(cursor) {
|
||||
case CursorImage::Hidden: SetCursor(nullptr); break;
|
||||
case CursorImage::Arrow: SetCursor((HCURSOR) _arrowCursor); break;
|
||||
case CursorImage::Cross: SetCursor((HCURSOR) _crossCursor); break;
|
||||
}
|
||||
}
|
||||
|
||||
double WindowsMouseManager::GetPixelScale()
|
||||
{
|
||||
return 1.0;
|
||||
}
|
20
Windows/WindowsMouseManager.h
Normal file
20
Windows/WindowsMouseManager.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
#include "Shared/Interfaces/IMouseManager.h"
|
||||
|
||||
class WindowsMouseManager : public IMouseManager
|
||||
{
|
||||
private:
|
||||
void* _arrowCursor;
|
||||
void* _crossCursor;
|
||||
|
||||
public:
|
||||
WindowsMouseManager();
|
||||
virtual ~WindowsMouseManager();
|
||||
|
||||
SystemMouseState GetSystemMouseState(void* rendererHandle);
|
||||
bool CaptureMouse(int32_t x, int32_t y, int32_t width, int32_t height, void* rendererHandle);
|
||||
void ReleaseMouse();
|
||||
void SetSystemMousePosition(int32_t x, int32_t y);
|
||||
void SetCursorImage(CursorImage cursor);
|
||||
double GetPixelScale();
|
||||
};
|
22
makefile
22
makefile
|
@ -94,11 +94,15 @@ ifneq ($(STATICLINK),false)
|
|||
LINKOPTIONS += -static-libgcc -static-libstdc++
|
||||
endif
|
||||
|
||||
ifeq ($(MESENOS),linux)
|
||||
LINKOPTIONS += -lX11
|
||||
endif
|
||||
|
||||
ifeq ($(MESENOS),osx)
|
||||
LINKOPTIONS += -framework Foundation -framework Cocoa
|
||||
endif
|
||||
|
||||
CXXFLAGS = -fPIC -Wall --std=c++17 $(MESENFLAGS) $(SDL2INC) -I $(realpath ./) -I $(realpath ./Core) -I $(realpath ./Utilities) -I $(realpath ./Linux) -I $(realpath ./MacOS)
|
||||
CXXFLAGS = -fPIC -Wall --std=c++17 $(MESENFLAGS) $(SDL2INC) -I $(realpath ./) -I $(realpath ./Core) -I $(realpath ./Utilities) -I $(realpath ./Sdl) -I $(realpath ./Linux) -I $(realpath ./MacOS)
|
||||
OBJCXXFLAGS = $(CXXFLAGS) -framework Foundation -framework Cocoa
|
||||
CFLAGS = -fPIC -Wall $(MESENFLAGS)
|
||||
|
||||
|
@ -121,8 +125,8 @@ COREOBJ := $(CORESRC:.cpp=.o)
|
|||
UTILSRC := $(shell find Utilities -name '*.cpp' -o -name '*.c')
|
||||
UTILOBJ := $(addsuffix .o,$(basename $(UTILSRC)))
|
||||
|
||||
LINUXSRC := $(shell find Linux -name '*.cpp')
|
||||
LINUXOBJ := $(LINUXSRC:.cpp=.o)
|
||||
SDLSRC := $(shell find Sdl -name '*.cpp')
|
||||
SDLOBJ := $(SDLSRC:.cpp=.o)
|
||||
|
||||
SEVENZIPSRC := $(shell find SevenZip -name '*.c')
|
||||
SEVENZIPOBJ := $(SEVENZIPSRC:.c=.o)
|
||||
|
@ -130,6 +134,13 @@ SEVENZIPOBJ := $(SEVENZIPSRC:.c=.o)
|
|||
LUASRC := $(shell find Lua -name '*.c')
|
||||
LUAOBJ := $(LUASRC:.c=.o)
|
||||
|
||||
ifeq ($(MESENOS),linux)
|
||||
LINUXSRC := $(shell find Linux -name '*.cpp')
|
||||
else
|
||||
LINUXSRC :=
|
||||
endif
|
||||
LINUXOBJ := $(LINUXSRC:.cpp=.o)
|
||||
|
||||
ifeq ($(MESENOS),osx)
|
||||
MACOSSRC := $(shell find MacOS -name '*.mm')
|
||||
else
|
||||
|
@ -183,10 +194,10 @@ pgohelper: InteropDLL/$(OBJFOLDER)/$(SHAREDLIB)
|
|||
%.o: %.mm
|
||||
$(CXX) $(OBJCXXFLAGS) -c $< -o $@
|
||||
|
||||
InteropDLL/$(OBJFOLDER)/$(SHAREDLIB): $(SEVENZIPOBJ) $(LUAOBJ) $(UTILOBJ) $(COREOBJ) $(LIBEVDEVOBJ) $(LINUXOBJ) $(DLLOBJ) $(MACOSOBJ)
|
||||
InteropDLL/$(OBJFOLDER)/$(SHAREDLIB): $(SEVENZIPOBJ) $(LUAOBJ) $(UTILOBJ) $(COREOBJ) $(SDLOBJ) $(LIBEVDEVOBJ) $(LINUXOBJ) $(DLLOBJ) $(MACOSOBJ)
|
||||
mkdir -p bin
|
||||
mkdir -p InteropDLL/$(OBJFOLDER)
|
||||
$(CXX) $(CXXFLAGS) $(LINKOPTIONS) $(LINKCHECKUNRESOLVED) -shared -o $(SHAREDLIB) $(DLLOBJ) $(SEVENZIPOBJ) $(LUAOBJ) $(LINUXOBJ) $(MACOSOBJ) $(LIBEVDEVOBJ) $(UTILOBJ) $(COREOBJ) $(SDL2INC) -pthread $(FSLIB) $(SDL2LIB) $(LIBEVDEVLIB)
|
||||
$(CXX) $(CXXFLAGS) $(LINKOPTIONS) $(LINKCHECKUNRESOLVED) -shared -o $(SHAREDLIB) $(DLLOBJ) $(SEVENZIPOBJ) $(LUAOBJ) $(LINUXOBJ) $(MACOSOBJ) $(LIBEVDEVOBJ) $(UTILOBJ) $(SDLOBJ) $(COREOBJ) $(SDL2INC) -pthread $(FSLIB) $(SDL2LIB) $(LIBEVDEVLIB)
|
||||
cp $(SHAREDLIB) bin/pgohelperlib.so
|
||||
mv $(SHAREDLIB) InteropDLL/$(OBJFOLDER)
|
||||
|
||||
|
@ -200,6 +211,7 @@ clean:
|
|||
rm -r -f $(COREOBJ)
|
||||
rm -r -f $(UTILOBJ)
|
||||
rm -r -f $(LINUXOBJ) $(LIBEVDEVOBJ)
|
||||
rm -r -f $(SDLOBJ)
|
||||
rm -r -f $(SEVENZIPOBJ)
|
||||
rm -r -f $(LUAOBJ)
|
||||
rm -r -f $(MACOSOBJ)
|
||||
|
|
Loading…
Reference in a new issue