-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[games] Mouse support #67
[games] Mouse support #67
Conversation
static int m_mouseStateY; | ||
for (std::vector<MOUSE::IMouseHandler*>::iterator it = m_mouseHandlers.begin(); it != m_mouseHandlers.end(); ++it) | ||
{ | ||
if ((*it)->OnMouseMotion(newEvent.motion.x - m_mouseStateX, newEvent.motion.y - m_mouseStateY)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The XBMC_Event
struct has fields for relative coordinates, why don't we use those? If we are given relative coords, and libretro requires relative coords, there shouldn't be any need to ever touch absolute positions. It should be possible to transfer dx and dy to libretro without any addition or subtraction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't find anthing that stores relative coordinates. there's xrel/yrel, but that's a different thing. From what I can see x/y are the absolute coordinate inside kodi window, xrel/yrel are the absolute coordinates relative to the screen 0,0 position. If kodi is running in fullscreen mode then they are the same. There are no other values set in https://github.com/xbmc/xbmc/blob/master/xbmc/windowing/WinEventsX11.cpp#L546. I could only find the relative position being calculated in MouseStat: https://github.com/xbmc/xbmc/blob/master/xbmc/input/MouseStat.cpp#L52.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, not a problem. Add a second mouse motion to IMouseHandler interface for absolute positions. Then create a IMouseHandler to wrap CGameClientMouse that accepts absolute coordinates and translates them to relative coordinates. The handler should be placed in xbmc/input/mouse/generic
because this is a class that describes generic behavior of a mouse. Our goal is to isolate all mouse handling logic so that it doesn't become entangled with any other dependencies.
handled = true; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you refactor the above code to only use 1 for loop?
game_input_event event; | ||
|
||
event.type = GAME_INPUT_EVENT_DIGITAL_BUTTON; | ||
event.port = -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here i'm not sure if that's the correct event type / port. Because the code in https://github.com/kodi-game/game.libretro/pull/7/files#diff-97dc480240fc0f2c40a1732397d7adecR148 feels like a hack now. (checking for -1)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup. total hack and something we should avoid
I've rethought our approach. Let's create mice controller profiles that can be mapped in the controller dialog. Then we add |
Don't add OpenMouse() to the game API, i realized that mouse support is only specified in addon.xml so we should open the mouse in CGameClient like we're doing now. But add the port #defines to detect mouse or joystick. Then you can use the port as a key in CLibretroInputDevice. |
Mouse movement is working again (with https://github.com/fetzerch/game.libretro.scummvm/tree/mouse, and https://github.com/fetzerch/game.libretro/tree/mouse). Couldn't yet get the buttons to work. They seem to be registered in game.libretro LibretroDeviceInput and also buttons are queried by the core but they don't trigger any action it seems. I'll do the refactoring of xbmc/input/InputManager.cpp once it's working again. One thing I noticed also is that only the first matching controller mapping is taken into account, hence I think that the joypad is no longer functioning. Not sure if there's a quick workaround. Btw: In case you also want to try this, just load scummvm in standalone mode. It has the ingame menu where you can use the mouse already without any games registered. |
@fetzerch I sent you a fix that refactors some stuff out of CInputManager |
fbab078
to
713bdf4
Compare
} | ||
|
||
void CInputManager::UnregisterMouseHandler(MOUSE::IMouseInputHandler* handler) | ||
{ | ||
auto it = m_mouseHandlers.find(handler); | ||
auto it = std::find_if(m_mouseHandlers.begin(), m_mouseHandlers.end(), | ||
[handler](const std::pair<MOUSE::IMouseInputHandler*, std::unique_ptr<MOUSE::IMouseDriverHandler>>& element) { return element.first == handler; }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you break this up into multiple lines?
auto it = std::find_if(m_mouseHandlers.begin(), m_mouseHandlers.end(),
[handler](const std::pair<MOUSE::IMouseInputHandler*, std::unique_ptr<MOUSE::IMouseDriverHandler>>& element)
{
return element.first == handler;
});
if (it == m_mouseHandlers.end()) | ||
m_mouseHandlers[handler].reset(new MOUSE::CMouseInputHandling(handler, m_mouseButtonMap.get())); | ||
m_mouseHandlers.emplace_back(std::make_pair(handler, std::unique_ptr<MOUSE::IMouseDriverHandler>(new MOUSE::CMouseInputHandling(handler, m_mouseButtonMap.get())))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want mouse handlers to be processed in the same order as RegisterMouseHandler() is called, or should priority be given to the most-recently registered mouse handler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd find it easier to understand if they are called in the registered order. If there's a reason for doing it the other way, we can change it.
@@ -284,7 +284,7 @@ class CInputManager : public ISettingCallback | |||
CCriticalSection m_actionMutex; | |||
|
|||
std::vector<KEYBOARD::IKeyboardHandler*> m_keyboardHandlers; | |||
std::map<MOUSE::IMouseInputHandler*, std::unique_ptr<MOUSE::IMouseDriverHandler>> m_mouseHandlers; | |||
std::vector<std::pair<MOUSE::IMouseInputHandler*, std::unique_ptr<MOUSE::IMouseDriverHandler>>> m_mouseHandlers; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest:
typedef std::pair<MOUSE::IMouseInputHandler*, std::unique_ptr<MOUSE::IMouseDriverHandler>> MouseHandlerHandle;
std::vector<MouseHandlerHandle> m_mouseHandlers;
@@ -965,10 +965,12 @@ void CGameClient::CloseKeyboard(void) | |||
void CGameClient::OpenMouse(void) | |||
{ | |||
m_mouse.reset(new CGameClientMouse(this, m_pStruct)); | |||
OpenPort(GAME_INPUT_PORT_MOUSE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This opens a joystick handler on the mouse port
Can you link your PR description to all the other open PRs that have to do with mouse support? xbmc, game.libretro, game.libretro.scummvm, kodi-game-controllers... I think we're up to 4 repos now. |
sure, Updated PR description |
|
||
if (controller->LoadLayout()) | ||
{ | ||
CloseMouse(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mouse port is guaranteed to be open by now due to the check at the beginning of this function, so this line isn't needed
We can map mouse buttons the same way we map keyboard buttons. We need a layer similar to We can add support for mapping mouse buttons by having |
Guess this can also be copied to or used by the Trackball in the (Xgaming) X-Arcade Tankstick. https://shop.xgaming.com/products/x-arcade-tankstick-trackball-usb-included Trackball inside the X-Arcade Tankstick should really work like any PS2 or USB HID mouse. https://github.com/kodi-game/peripheral.xarcade Know that @garbear have a X-Arcade Tankstic but not sure if he tested the Trackball? https://en.wikipedia.org/wiki/List_of_trackball_arcade_games Tip is above link which lists classic trackball games, most of which works in MAME emulator. |
Thanks for the links, the trackball works like a mouse so it's usable with Kodi, but the resolution is really high so it goes really slow. for it to be useful in games we might need a setting for speed gain |
@@ -21,6 +21,8 @@ | |||
|
|||
#include "input/mouse/IMouseInputHandler.h" | |||
|
|||
#define MOUSE_CONTROLLER_ID "game.controller.mouse" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way we can avoid defining this here and use the value from here? https://github.com/garbear/xbmc/blob/retroplayer-mouse/xbmc/input/mouse/MouseWindowingButtonMap.cpp#L28
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kind of like how DEFAULT_CONTROLLER_ID is done, but it'd be nice if we could keep this #define inside MouseWindowingButtonMap.cpp and access it through its ControllerID() function
@@ -114,7 +112,7 @@ void CGameClientMouse::OnButtonRelease(const std::string& button) | |||
|
|||
event.type = GAME_INPUT_EVENT_DIGITAL_BUTTON; | |||
event.port = GAME_INPUT_PORT_MOUSE; | |||
event.controller_id = CONTROLLER_NAME; | |||
event.controller_id = MOUSE_CONTROLLER_ID; | |||
event.feature_name = button.c_str(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, button
is the name of a feature of game.controller.default, so game.controller.default serves as the "context" for this feature name. e.g. "left" is useless unless we know it's "left" for game.controller.mouse.
As I mentioned in my comment below, it'd be nice if the controller ID could come from the same source as the button name (CMouseWindowingButtonMap)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create a static MouseControllerID() function in CMouseWindowingButtonMap, or have a default constructed instance of CMouseWindowingButtonMap in CGameClientMouse?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both are undesirable. we need to pass the controller context to this class somehow. See CGameClientInput::ControllerID()
and notice how the context comes from CGameClient. CGameClientInput::ControllerID()
is then used to transfer the context to the port manager, which opens a port using that controller ID.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about adding a return value to CInputManager::RegisterMouseHandler
and let InputManager
return m_mouseButtonMap->ControllerID()
. That way we can easily keep CGameClientMouse
independent from the button map. A getter would also do, but since we call register anyway, that's much cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could work. Give it a try, and I'll see if it leads to any glaring problems.
@garbear is it the same for mouse speed at different resolutions in all emulators or? So on a 2160p (4K) display it might even be slower then. Would then be nice if could set different default speed for mouse on different resolutions. If detect a 240p display then it runs mouse at 1x speed by default. |
@fetzerch what's left before we merge? do you want to add support for mapping the mouse and emulating the mouse with a joystick, or merge this first and add that later? |
Wanted to ask you ;) For this PR, just the MOUSE_CONTROLLER_ID. Haven't yet found a nice way of doing it. If we pass in the controller when creating creating the gameclientmouse, we could access it from there. But we need to access it also when loading the addon and have to get it from buttonmap (which is created in inputmanager). Mouse mapping, I'd say we do separately. (Is there an option to disable it in the dialog for the moment?) For game.libretro, we have open the thing with the port number and the logging of the libretro key. Then for the addons it's just removing the game.controller.default. I think we don't need that explicitly now that we load the mouse controller explicitly. |
I guess for now we should just copy the default controller thing, define the mouse ID in MouseWindowingButtonMap.h, add this line to GameClient.cpp: #include "input/mouse/MouseWindowingButtonMap.h" // for MOUSE_CONTROLLER_ID then pass the ID to CGameClientMouse.
For now we can simply not ship game.controller.mouse. Then it won't show up in the GUI, but it'll still be usable because the Kodi -> mouse translations are hardcoded in MouseWindowingButtonMap.cpp. |
Updated. If we don't ship the addon, it'll not work because in OpenMouse we need to call UpdatePort so that game.libretro gets informed. |
Let me know if you want me to squash the changes |
/*! \brief Registers a handler to be called on mouse input (e.g a game client). | ||
* | ||
* \param handler The handler to call on mouse input. | ||
* \return[in] The controller ID of the button map used to translate from windowing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say \return The controller ID that serves as a context for incoming events
Yes, squash the changes and i'll do a review of the full patch |
ddc6645
to
d024329
Compare
The changes here look good. I sent you a PR for build system fixes for xcode and autotools. |
9c309ed
to
21964af
Compare
Game API v1.0.28: - Define keyboard and mouse ports - Use XBMCVKey for keyboard keys - Add XBMC_vkeys.h to addon bindings
Is that it? What's left for this PR? |
I'll test why buttons are not working anymore, then i'll squash both PRs and push another version. |
850ea8e
to
d002851
Compare
PRs updated. dosbox and scummvm work with mouse and joystick. Still haven't fully figured out how game.controller.kodi is supposed to come into play. but maybe we can do this independently. |
you mean game.controller.mouse? it's needed for button mapping, but it's ok that it's missing now because the feature names are hardcoded in MouseWindowingButtonMap.cpp Ready for merge across the PRs? |
from my side, yes. everything tested and pushed |
for (unsigned int i = 0; i < m_ports.size(); i++) | ||
ClosePort(i); | ||
for (const auto &it : m_ports) | ||
ClosePort(it.first); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ClosePort() modifies m_ports, which i think invalidates the iterator. I'll fix once i merge this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should do it: e762427
[addons] add initial base add-on C++ support
Adds mouse support for Emulators like ScummVM or Dosbox. Fixes #6
Related changes:
Known issues:
GAME_INPUT_PORT_MOUSE
)) (fixed by kodi-game/game.libretro@c62477c)