From 99d5ad221572cdcc59cc36442bd4d11bf66f17c5 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Tue, 17 Jan 2012 23:48:13 +0200 Subject: [PATCH] Make mouse be ordinary keys instead of being special --- include/core/controllerframe.hpp | 40 ++++++++++++++++++++++++ include/core/dispatch.hpp | 26 ---------------- include/core/keymapper.hpp | 6 +++- include/core/window.hpp | 7 ----- src/core/controller.cpp | 49 +++++++++++++++++++++++++++++ src/core/controller_gamepad.cpp | 10 ++++++ src/core/controller_justifier.cpp | 10 ++++++ src/core/controller_justifiers.cpp | 10 ++++++ src/core/controller_mouse.cpp | 10 ++++++ src/core/controller_multitap.cpp | 10 ++++++ src/core/controller_none.cpp | 10 ++++++ src/core/controller_superscope.cpp | 10 ++++++ src/core/controllerframe.cpp | 20 ++++++++++++ src/core/dispatch.cpp | 24 -------------- src/core/framebuffer.cpp | 19 +++++++++++- src/core/keymapper.cpp | 10 ++++-- src/core/mainloop.cpp | 20 ------------ src/core/window.cpp | 22 ------------- src/plat-sdl/graphicsfn.cpp | 50 ++++++++++++++++++------------ src/plat-wxwidgets/mainwindow.cpp | 30 +++++++++++++----- 20 files changed, 263 insertions(+), 130 deletions(-) diff --git a/include/core/controllerframe.hpp b/include/core/controllerframe.hpp index ba18e881..4533ae6b 100644 --- a/include/core/controllerframe.hpp +++ b/include/core/controllerframe.hpp @@ -351,6 +351,18 @@ struct porttype_info * Parameter port: Port to set to. */ virtual void set_core_controller(unsigned port) const throw() = 0; +/** + * Does the controller have analog function? + * + * Parameter controller: Controller number. + */ + virtual bool is_analog(unsigned controller) const throw() = 0; +/** + * Does the controller have mouse-type function? + * + * Parameter controller: Controller number. + */ + virtual bool is_mouse(unsigned controller) const throw() = 0; /** * Port type value. */ @@ -818,6 +830,26 @@ public: unsigned port = (pcid / MAX_CONTROLLERS_PER_PORT) % MAX_PORTS; return pinfo[port]->button_id(pcid % MAX_CONTROLLERS_PER_PORT, lbid); } +/** + * Does the specified controller have analog function. + * + * Parameter pcid: Physical controller id. + */ + bool is_analog(unsigned pcid) + { + unsigned port = (pcid / MAX_CONTROLLERS_PER_PORT) % MAX_PORTS; + return pinfo[port]->is_analog(pcid % MAX_CONTROLLERS_PER_PORT); + } +/** + * Does the specified controller have mouse-type function. + * + * Parameter pcid: Physical controller id. + */ + bool is_mouse(unsigned pcid) + { + unsigned port = (pcid / MAX_CONTROLLERS_PER_PORT) % MAX_PORTS; + return pinfo[port]->is_mouse(pcid % MAX_CONTROLLERS_PER_PORT); + } private: size_t totalsize; unsigned char memory[MAXIMUM_CONTROLLER_FRAME_SIZE]; @@ -1136,6 +1168,14 @@ public: * Returns: The physical button id, or -1 if no such button. */ int button_id(unsigned pcid, unsigned lbid) throw(); +/** + * TODO: Document. + */ + bool is_analog(unsigned pcid) throw(); +/** + * TODO: Document. + */ + bool is_mouse(unsigned pcid) throw(); private: const porttype_info* porttypeinfo[MAX_PORTS]; porttype_t porttypes[MAX_PORTS]; diff --git a/include/core/dispatch.hpp b/include/core/dispatch.hpp index 783f162a..ffd6055a 100644 --- a/include/core/dispatch.hpp +++ b/include/core/dispatch.hpp @@ -111,23 +111,6 @@ public: * Call all on_close() handlers. */ static void do_close() throw(); -/** - * Click or release on window was receivied. - * - * The default handler does nothing. - * - * Parameter x: The x-coordinate of the click. May be negative or otherwise out of screen. - * Parameter y: The y-coordinate of the click. May be negative or otherwise out of screen. - * Parameter buttonmask: Bitfield giving current buttons held: - * Bit 0 => Left button is down/held. - * Bit 1 => Middle button is down/held. - * Bit 2 => Middle button is down/held. - */ - virtual void on_click(int32_t x, int32_t y, uint32_t buttonmask); -/** - * Call all on_click() handlers. - */ - static void do_click(int32_t x, int32_t y, uint32_t buttonmask) throw(); /** * Sound mute/unmute status might have been changed. * @@ -388,15 +371,6 @@ public: * Get name of target. */ const std::string& get_name() throw(); -/** - * Set window main screen compensation parameters. This is used for mouse click reporting. - * - * parameter xoffset: X coordinate of origin. - * parameter yoffset: Y coordinate of origin. - * parameter hscl: Horizontal scaling factor. - * parameter vscl: Vertical scaling factor. - */ - static void do_click_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl); /** * Render buffer needs to be (possibly) resized, so that graphics plugin can update the mappings. * diff --git a/include/core/keymapper.hpp b/include/core/keymapper.hpp index d5e19f3e..f6436960 100644 --- a/include/core/keymapper.hpp +++ b/include/core/keymapper.hpp @@ -327,8 +327,12 @@ public: * Set callback requests on/off */ void request_hook_callback(bool state); +/** + * Get status value. + */ + signed get_value(); private: - unsigned state; + signed state; enum type ktype; short last_rawval; short cal_left; diff --git a/include/core/window.hpp b/include/core/window.hpp index 2de9487a..7249b7d4 100644 --- a/include/core/window.hpp +++ b/include/core/window.hpp @@ -534,13 +534,6 @@ struct platform static void run_queues() throw(); }; -/** - * Send a mouse click. - * - * Call from UI thread. - */ -void send_mouse_click(long x, long y, uint32_t buttons); - template void functor_call_helper(void* args) { diff --git a/src/core/controller.cpp b/src/core/controller.cpp index 59fc7f75..1fabd0fd 100644 --- a/src/core/controller.cpp +++ b/src/core/controller.cpp @@ -51,6 +51,24 @@ namespace controls.button(x, bid, newstate); } + void send_analog(unsigned lcid, int32_t x, int32_t y) + { + int pcid = controls.lcid_to_pcid(lcid); + if(pcid < 0) { + messages << "Controller #" << (lcid + 1) << " not present" << std::endl; + return; + } + if(controls.is_analog(pcid) < 0) { + messages << "Controller #" << (lcid + 1) << " is not analog" << std::endl; + return; + } + auto g2 = get_framebuffer_size(); + if(controls.is_mouse(pcid)) { + controls.analog(pcid, x - g2.first / 2, y - g2.second / 2); + } else + controls.analog(pcid, x / 2 , y / 2); + } + function_ptr_command autofire("autofire", "Set autofire pattern", "Syntax: autofire ...\nSet autofire pattern\n", [](tokensplitter& t) throw(std::bad_alloc, std::runtime_error) { @@ -139,6 +157,32 @@ namespace std::string button; }; + class analog_action : public command + { + public: + analog_action(const std::string& cmd, unsigned _controller) + throw(std::bad_alloc) + : command(cmd) + { + controller = _controller; + } + ~analog_action() throw() {} + void invoke(const std::string& args) throw(std::bad_alloc, std::runtime_error) + { + if(args != "") + throw std::runtime_error("This command does not take parameters"); + keygroup* mouse_x = keygroup::lookup_by_name("mouse_x"); + keygroup* mouse_y = keygroup::lookup_by_name("mouse_y"); + if(!mouse_x || !mouse_y) { + messages << "Controller analog function not available without mouse" << std::endl; + return; + } + send_analog(controller, mouse_x->get_value(), mouse_y->get_value()); + } + private: + unsigned controller; + }; + class button_action_helper { public: @@ -165,6 +209,11 @@ namespace y = cstr + get_logical_button_name(i); our_commands.insert(new button_action(x, j, k, y)); } + for(unsigned k = 0; k < 8; ++k) { + std::string x = "controllerXanalog"; + x[10] = 49 + k; + our_commands.insert(new analog_action(x, k)); + } } ~button_action_helper() { diff --git a/src/core/controller_gamepad.cpp b/src/core/controller_gamepad.cpp index 8b02d76e..1d826655 100644 --- a/src/core/controller_gamepad.cpp +++ b/src/core/controller_gamepad.cpp @@ -106,5 +106,15 @@ namespace return; snes_set_controller_port_device(port != 0, SNES_DEVICE_JOYPAD); } + + bool is_analog(unsigned controller) const throw() + { + return false; + } + + bool is_mouse(unsigned controller) const throw() + { + return false; + } } gamepad; } diff --git a/src/core/controller_justifier.cpp b/src/core/controller_justifier.cpp index f99c941d..c0a44b27 100644 --- a/src/core/controller_justifier.cpp +++ b/src/core/controller_justifier.cpp @@ -113,5 +113,15 @@ namespace return; snes_set_controller_port_device(port != 0, SNES_DEVICE_JUSTIFIER); } + + bool is_analog(unsigned controller) const throw() + { + return (controller == 0); + } + + bool is_mouse(unsigned controller) const throw() + { + return false; + } } justifier; } diff --git a/src/core/controller_justifiers.cpp b/src/core/controller_justifiers.cpp index c9d6cdc7..ba239ac0 100644 --- a/src/core/controller_justifiers.cpp +++ b/src/core/controller_justifiers.cpp @@ -127,5 +127,15 @@ namespace return; snes_set_controller_port_device(port != 0, SNES_DEVICE_JUSTIFIERS); } + + bool is_analog(unsigned controller) const throw() + { + return (controller < 2); + } + + bool is_mouse(unsigned controller) const throw() + { + return false; + } } justifiers; } diff --git a/src/core/controller_mouse.cpp b/src/core/controller_mouse.cpp index f157a332..16aef20f 100644 --- a/src/core/controller_mouse.cpp +++ b/src/core/controller_mouse.cpp @@ -113,5 +113,15 @@ namespace return; snes_set_controller_port_device(port != 0, SNES_DEVICE_MOUSE); } + + bool is_analog(unsigned controller) const throw() + { + return (controller == 0); + } + + bool is_mouse(unsigned controller) const throw() + { + return (controller == 0); + } } mouse; } diff --git a/src/core/controller_multitap.cpp b/src/core/controller_multitap.cpp index e1e6ffa2..922e268a 100644 --- a/src/core/controller_multitap.cpp +++ b/src/core/controller_multitap.cpp @@ -120,5 +120,15 @@ namespace return; snes_set_controller_port_device(port != 0, SNES_DEVICE_MULTITAP); } + + bool is_analog(unsigned controller) const throw() + { + return false; + } + + bool is_mouse(unsigned controller) const throw() + { + return false; + } } multitap; } diff --git a/src/core/controller_none.cpp b/src/core/controller_none.cpp index fca82a2a..e7585904 100644 --- a/src/core/controller_none.cpp +++ b/src/core/controller_none.cpp @@ -64,5 +64,15 @@ namespace return; snes_set_controller_port_device(port != 0, SNES_DEVICE_NONE); } + + bool is_analog(unsigned controller) const throw() + { + return false; + } + + bool is_mouse(unsigned controller) const throw() + { + return false; + } } none; } diff --git a/src/core/controller_superscope.cpp b/src/core/controller_superscope.cpp index 1cd2f1d1..434e3125 100644 --- a/src/core/controller_superscope.cpp +++ b/src/core/controller_superscope.cpp @@ -125,5 +125,15 @@ namespace return; snes_set_controller_port_device(port != 0, SNES_DEVICE_SUPER_SCOPE); } + + bool is_analog(unsigned controller) const throw() + { + return (controller == 0); + } + + bool is_mouse(unsigned controller) const throw() + { + return false; + } } superscope; } diff --git a/src/core/controllerframe.cpp b/src/core/controllerframe.cpp index c0d7a70b..54b77c7a 100644 --- a/src/core/controllerframe.cpp +++ b/src/core/controllerframe.cpp @@ -79,6 +79,16 @@ namespace std::cerr << "Attempt to set core port type to INVALID port type" << std::endl; exit(1); } + + bool is_analog(unsigned controller) const throw() + { + return false; + } + + bool is_mouse(unsigned controller) const throw() + { + return false; + } }; porttype_invalid& get_invalid_port_type() @@ -750,3 +760,13 @@ controller_frame controller_state::commit(controller_frame controls) throw() _committed = controls; return _committed; } + +bool controller_state::is_analog(unsigned pcid) throw() +{ + return _input.is_analog(pcid); +} + +bool controller_state::is_mouse(unsigned pcid) throw() +{ + return _input.is_mouse(pcid); +} diff --git a/src/core/dispatch.cpp b/src/core/dispatch.cpp index 3f392404..3513fcab 100644 --- a/src/core/dispatch.cpp +++ b/src/core/dispatch.cpp @@ -146,22 +146,6 @@ void information_dispatch::do_close() throw() } } -void information_dispatch::on_click(int32_t x, int32_t y, uint32_t buttonmask) -{ - //Do nothing. -} - -void information_dispatch::do_click(int32_t x, int32_t y, uint32_t buttonmask) throw() -{ - x = (x - vc_xoffset) / vc_hscl; - y = (y - vc_yoffset) / vc_vscl; - for(auto& i : dispatch()) { - START_EH_BLOCK - i->on_click(x, y, buttonmask); - END_EH_BLOCK(i, "on_click"); - } -} - void information_dispatch::on_sound_unmute(bool unmuted) { //Do nothing. @@ -492,14 +476,6 @@ void information_dispatch::update_dumpers(bool nocalls) throw() } } -void information_dispatch::do_click_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl) -{ - vc_xoffset = xoffset; - vc_yoffset = yoffset; - vc_hscl = hscl; - vc_vscl = vscl; -} - void information_dispatch::on_set_screen(screen& scr) { //Do nothing. diff --git a/src/core/framebuffer.cpp b/src/core/framebuffer.cpp index 2ca667ec..27f099ca 100644 --- a/src/core/framebuffer.cpp +++ b/src/core/framebuffer.cpp @@ -210,6 +210,8 @@ void redraw_framebuffer() void render_framebuffer() { + static uint32_t val1, val2, val3, val4; + uint32_t nval1, nval2, nval3, nval4; render_info& ri = get_read_buffer(); main_screen.reallocate(ri.fbuf.width * ri.hscl + ri.lgap + ri.rgap, ri.fbuf.height * ri.vscl + ri.tgap + ri.bgap); @@ -218,7 +220,22 @@ void render_framebuffer() ri.rq.run(main_screen); information_dispatch::do_set_screen(main_screen); //We would want divide by 2, but we'll do it ourselves in order to do mouse. - information_dispatch::do_click_compensation(ri.lgap, ri.tgap, 1, 1); + keygroup* mouse_x = keygroup::lookup_by_name("mouse_x"); + keygroup* mouse_y = keygroup::lookup_by_name("mouse_y"); + nval1 = ri.lgap; + nval2 = ri.tgap; + nval3 = ri.fbuf.width * ri.hscl + ri.rgap; + nval4 = ri.fbuf.height * ri.vscl + ri.bgap; + if(mouse_x && (nval1 != val1 || nval3 != val3)) + mouse_x->change_calibration(-static_cast(ri.lgap), ri.lgap, ri.fbuf.width * ri.hscl + ri.rgap, + 0.5); + if(mouse_y && (nval2 != val2 || nval4 != val4)) + mouse_y->change_calibration(-static_cast(ri.tgap), ri.tgap, ri.fbuf.height * ri.vscl + ri.bgap, + 0.5); + val1 = nval1; + val2 = nval2; + val3 = nval3; + val4 = nval4; buffering.end_read(); } diff --git a/src/core/keymapper.cpp b/src/core/keymapper.cpp index 7531a830..45d1d02d 100644 --- a/src/core/keymapper.cpp +++ b/src/core/keymapper.cpp @@ -417,13 +417,15 @@ void keygroup::set_position(short pos, const modifier_set& modifiers) throw() if(requests_hook) lua_callback_keyhook(keyname, get_parameters()); double x = compensate2(compensate(pos)); - unsigned tmp; + signed tmp; bool left, right, up, down; bool oleft, oright, oup, odown; switch(ktype) { case KT_DISABLED: - case KT_MOUSE: return; + case KT_MOUSE: + state = pos - cal_center; + break; case KT_KEY: case KT_PRESSURE_0M: case KT_PRESSURE_0P: @@ -557,6 +559,10 @@ std::set keygroup::get_keys() throw(std::bad_alloc) return r; } +signed keygroup::get_value() +{ + return state; +} namespace { diff --git a/src/core/mainloop.cpp b/src/core/mainloop.cpp index 1bb89ae5..65206fe4 100644 --- a/src/core/mainloop.cpp +++ b/src/core/mainloop.cpp @@ -669,26 +669,6 @@ namespace } on_quit_prompt = false; } - - void send_analog(unsigned acid, int32_t x, int32_t y) - { - auto g2 = get_framebuffer_size(); - if(controls.acid_is_mouse(acid)) { - controls.analog(acid, x - g2.first / 2, y - g2.second / 2); - } else - controls.analog(acid, x / 2 , y / 2); - } - - void on_click(int32_t x, int32_t y, uint32_t buttonmask) throw() - { - if(buttonmask & ~prev_mouse_mask & 1) - send_analog(0, x, y); - if(buttonmask & ~prev_mouse_mask & 2) - send_analog(1, x, y); - if(buttonmask & ~prev_mouse_mask & 4) - send_analog(2, x, y); - prev_mouse_mask = buttonmask; - } } mywcb; //If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load diff --git a/src/core/window.cpp b/src/core/window.cpp index 22c8fae4..6cce4164 100644 --- a/src/core/window.cpp +++ b/src/core/window.cpp @@ -538,28 +538,6 @@ namespace { graphics_plugin::notify_status(); } - - struct handle_mouse_request - { - long x; - long y; - uint32_t mask; - }; - - void _handle_mouse(void* args) - { - struct handle_mouse_request* x = reinterpret_cast(args); - information_dispatch::do_click(x->x, x->y, x->mask); - } -} - -void send_mouse_click(long x, long y, uint32_t buttons) -{ - struct handle_mouse_request z; - z.x = x; - z.y = y; - z.mask = buttons; - platform::queue(_handle_mouse, &z, true); } mutex& platform::msgbuf_lock() throw() diff --git a/src/plat-sdl/graphicsfn.cpp b/src/plat-sdl/graphicsfn.cpp index 00371025..5a89fddd 100644 --- a/src/plat-sdl/graphicsfn.cpp +++ b/src/plat-sdl/graphicsfn.cpp @@ -288,6 +288,12 @@ namespace { platform::queue(emu_handle_quit_signal, NULL, false); } + + keygroup mouse_x("mouse_x", keygroup::KT_MOUSE); + keygroup mouse_y("mouse_y", keygroup::KT_MOUSE); + keygroup mouse_l("mouse_left", keygroup::KT_KEY); + keygroup mouse_m("mouse_center", keygroup::KT_KEY); + keygroup mouse_r("mouse_right", keygroup::KT_KEY); } void notify_emulator_exit() @@ -339,34 +345,40 @@ void ui_loop() ui_panic(); while(true); } - if(e.type == SDL_MOUSEBUTTONDOWN) { - int i; - switch(e.button.button) { - case SDL_BUTTON_LEFT: - mouse_state |= 1; - break; - case SDL_BUTTON_MIDDLE: - mouse_state |= 2; - break; - case SDL_BUTTON_RIGHT: - mouse_state |= 4; - break; - }; - send_mouse_click(e.button.x, e.button.y, mouse_state); + if(e.type == SDL_MOUSEMOTION && special_mode == SPECIALMODE_NORMAL) { + platform::queue(keypress(modifier_set(), mouse_x, e.motion.x - 6)); + platform::queue(keypress(modifier_set(), mouse_y, e.motion.y - 6)); } - if(e.type == SDL_MOUSEBUTTONUP) { + if(e.type == SDL_MOUSEBUTTONDOWN && special_mode == SPECIALMODE_NORMAL) { + int i; + platform::queue(keypress(modifier_set(), mouse_x, e.button.x - 6)); + platform::queue(keypress(modifier_set(), mouse_y, e.button.y - 6)); switch(e.button.button) { case SDL_BUTTON_LEFT: - mouse_state &= ~1; + platform::queue(keypress(modifier_set(), mouse_l, 1)); break; case SDL_BUTTON_MIDDLE: - mouse_state &= ~2; + platform::queue(keypress(modifier_set(), mouse_m, 1)); break; case SDL_BUTTON_RIGHT: - mouse_state &= ~4; + platform::queue(keypress(modifier_set(), mouse_r, 1)); + break; + }; + } + if(e.type == SDL_MOUSEBUTTONUP && special_mode == SPECIALMODE_NORMAL) { + platform::queue(keypress(modifier_set(), mouse_x, e.button.x - 6)); + platform::queue(keypress(modifier_set(), mouse_y, e.button.y - 6)); + switch(e.button.button) { + case SDL_BUTTON_LEFT: + platform::queue(keypress(modifier_set(), mouse_l, 0)); + break; + case SDL_BUTTON_MIDDLE: + platform::queue(keypress(modifier_set(), mouse_m, 0)); + break; + case SDL_BUTTON_RIGHT: + platform::queue(keypress(modifier_set(), mouse_r, 0)); break; }; - send_mouse_click(e.button.x, e.button.y, mouse_state); } //Handle entering identify mode. if(identify_requested) { diff --git a/src/plat-wxwidgets/mainwindow.cpp b/src/plat-wxwidgets/mainwindow.cpp index 22ee2acd..4ca1bf80 100644 --- a/src/plat-wxwidgets/mainwindow.cpp +++ b/src/plat-wxwidgets/mainwindow.cpp @@ -118,22 +118,33 @@ namespace emulation_thread->join(); } + keygroup mouse_x("mouse_x", keygroup::KT_MOUSE); + keygroup mouse_y("mouse_y", keygroup::KT_MOUSE); + keygroup mouse_l("mouse_left", keygroup::KT_KEY); + keygroup mouse_m("mouse_center", keygroup::KT_KEY); + keygroup mouse_r("mouse_right", keygroup::KT_KEY); + keygroup mouse_i("mouse_inwindow", keygroup::KT_KEY); + void handle_wx_mouse(wxMouseEvent& e) { - static uint32_t mask = 0; + platform::queue(keypress(modifier_set(), mouse_x, e.GetX())); + platform::queue(keypress(modifier_set(), mouse_y, e.GetY())); + if(e.Entering()) + platform::queue(keypress(modifier_set(), mouse_i, 1)); + if(e.Leaving()) + platform::queue(keypress(modifier_set(), mouse_i, 0)); if(e.LeftDown()) - mask |= 1; + platform::queue(keypress(modifier_set(), mouse_l, 1)); if(e.LeftUp()) - mask &= ~1; + platform::queue(keypress(modifier_set(), mouse_l, 0)); if(e.MiddleDown()) - mask |= 2; + platform::queue(keypress(modifier_set(), mouse_m, 1)); if(e.MiddleUp()) - mask &= ~2; + platform::queue(keypress(modifier_set(), mouse_m, 0)); if(e.RightDown()) - mask |= 4; + platform::queue(keypress(modifier_set(), mouse_r, 1)); if(e.RightUp()) - mask &= ~4; - send_mouse_click(e.GetX(), e.GetY(), mask); + platform::queue(keypress(modifier_set(), mouse_r, 0)); } bool is_readonly_mode() @@ -619,6 +630,9 @@ wxwin_mainwindow::panel::panel(wxWindow* win) this->Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(panel::on_mouse), NULL, this); this->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(panel::on_mouse), NULL, this); this->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(panel::on_mouse), NULL, this); + this->Connect(wxEVT_MOTION, wxMouseEventHandler(panel::on_mouse), NULL, this); + this->Connect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(panel::on_mouse), NULL, this); + this->Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(panel::on_mouse), NULL, this); SetMinSize(wxSize(512, 448)); }