summaryrefslogblamecommitdiffstatshomepage
path: root/src/osd/modules/input/input_win32.cpp
blob: 49c211740c0da724b597d65b7efd910cc08439ca (plain) (tree)
1
2
3
4
5
6
7
8
9








                                                              

                        
 

                          





                            
                     
 
                    
 

                           
 
 

               

           







                                                                            




                                                                                           
 
                                     
         
                                                           

         
                                                             
         







                                                                                       

                                                                                                                                    






                                                                                                                                
                                                                                



                                                                               


          
                                                                          
         
                                                                                                     
         


                                  

  
 



                                                              
                                                                          
 
       
                                                                                                            




                                                                  
                                                                            
 

                                                                                                                    

         
                                                                                      
         

                                






                                                                                                                 
                                                                                        


                                     



                 
 



                                                              
                                                                          

       


                                                                                        


                                     


         
                                                       
         



                                                         
 
                                               







                                                                                                 

                                                                                                                                 

                                              


                                                                                                                                

                                                                                              




                                                                                                                



                                                                                            




                                                             























                                                             
 
                                       
                                                          


                                                                    
                                                           


                                                                                


                 
                                     
         

                                                                 
                                          


          
                                                                             

                                       











                                                             
         








                                          
                                                 

  
 



                                                              
                                                                    
 
       
                                                                                                   




                                                                  


                                                                         


                                    




                                                                                                        









                                                                                                             
 
                             


         
 



                                                              
                                                                                  






                                                     










                                                                           
         
                                    
                                                             
                 

                                                                   
                                                           


                                                                               


                                       
                                                                
                 

                                                                    
                                                           


                                                                                


                 
                            

  

 



                                                              
                                                               
 
       



                                               


                                                                                   
         

         
                                                       
         
                                                         
 
                                           

                                                                           
                               
                                        
                                                         
                 
                                                                  
                                                                                                                                  
                                         

                                                          






                                                                                                        

                                  































                                                                                                    

         
          
                                                                             
         
                                                                        











                                                             
         


                                                 
  
 














                                                                                   
         

         
                                                             
         

                                        
 





                                                                             
                 























                                                                                                                                          

                 


                              

  
 



                                                              
                                                                               

       
                                                                                                                 
         



                                                                  



                                                                                                                




                                                                                                

                                            



                                                                                                                                               


                 
                                                                                      
         









                                                                                                             
 
                             


         

                        

                  

                             



               


                                                                               
 



                        
                              
 


                                                                 
// license:BSD-3-Clause
// copyright-holders:Aaron Giles, Brad Hughes
//============================================================
//
//  input_win32.cpp - Win32 input implementation
//
//============================================================

#include "input_module.h"

#if defined(OSD_WINDOWS)

#include "input_windows.h"

#include "input_wincommon.h"

// osd/windows
#include "window.h"

// emu
#include "inpttype.h"

#include "strconv.h"

// standard windows headers
#include <tchar.h>


namespace osd {

namespace {

//============================================================
//  win32_keyboard_device
//============================================================

// This device is purely event driven so the implementation is in the module
class win32_keyboard_device : public event_based_device<KeyPressEventArgs>
{
public:
	win32_keyboard_device(std::string &&name, std::string &&id, input_module &module) :
		event_based_device(std::move(name), std::move(id), module),
		m_keyboard({{0}})
	{
	}

	virtual void reset() override
	{
		memset(&m_keyboard, 0, sizeof(m_keyboard));
	}

	virtual void configure(input_device &device) override
	{
		keyboard_trans_table const &table = keyboard_trans_table::instance();

		for (int keynum = 0; keynum < MAX_KEYS; keynum++)
		{
			input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
			TCHAR keyname[100];

			// generate the name
			// FIXME: GetKeyNameText gives bogus names for media keys and various other things
			// in many cases it ignores the "extended" bit and returns the key name corresponding to the scan code alone
			if (GetKeyNameText(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, std::size(keyname)) == 0)
				_sntprintf(keyname, std::size(keyname), TEXT("Scan%03d"), keynum);
			std::string name = text::from_tstring(keyname);

			// add the item to the device
			device.add_item(
					name,
					util::string_format("SCAN%03d", keynum),
					itemid,
					generic_button_get_state<std::uint8_t>,
					&m_keyboard.state[keynum]);
		}
	}

protected:
	virtual void process_event(KeyPressEventArgs const &args) override
	{
		m_keyboard.state[args.scancode] = args.event_id == INPUT_EVENT_KEYDOWN ? 0x80 : 0x00;
	}

private:
	keyboard_state m_keyboard;
};


//============================================================
//  keyboard_input_win32 - win32 keyboard input module
//============================================================

class keyboard_input_win32 : public wininput_module<win32_keyboard_device>
{
public:
	keyboard_input_win32() : wininput_module<win32_keyboard_device>(OSD_KEYBOARDINPUT_PROVIDER, "win32")
	{
	}

	virtual void input_init(running_machine &machine) override
	{
		wininput_module<win32_keyboard_device>::input_init(machine);

		// Add a single win32 keyboard device that we'll monitor using Win32
		create_device<win32_keyboard_device>(DEVICE_CLASS_KEYBOARD, "Win32 Keyboard 1", "Win32 Keyboard 1");
	}

	virtual bool handle_input_event(input_event eventid, void *eventdata) override
	{
		switch (eventid)
		{
		case INPUT_EVENT_KEYDOWN:
		case INPUT_EVENT_KEYUP:
			devicelist().for_each_device(
					[args = static_cast<KeyPressEventArgs const *>(eventdata)] (auto &device)
					{
						device.queue_events(args, 1);
					});
			return false; // we still want text input events to be generated

		default:
			return false;
		}
	}
};


//============================================================
//  win32_mouse_device
//============================================================

class win32_mouse_device : public event_based_device<MouseUpdateEventArgs>
{
public:
	win32_mouse_device(std::string &&name, std::string &&id, input_module &module) :
		event_based_device(std::move(name), std::move(id), module),
		m_mouse({0}),
		m_win32_mouse({{0}}),
		m_vscroll(0),
		m_hscroll(0)
	{
	}

	virtual void poll(bool relative_reset) override
	{
		event_based_device::poll(relative_reset);

		if (!relative_reset)
			return;

		CURSORINFO cursor_info = { 0 };
		cursor_info.cbSize = sizeof(CURSORINFO);
		GetCursorInfo(&cursor_info);

		// We only take over the mouse if the cursor isn't showing
		// This should happen anyway in mouse mode
		if (!(cursor_info.flags & CURSOR_SHOWING))
		{
			// We measure the position change from the previously set center position
			m_mouse.lX = (cursor_info.ptScreenPos.x - m_win32_mouse.last_point.x) * input_device::RELATIVE_PER_PIXEL;
			m_mouse.lY = (cursor_info.ptScreenPos.y - m_win32_mouse.last_point.y) * input_device::RELATIVE_PER_PIXEL;

			RECT window_pos = {0};
			GetWindowRect(
					dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window(),
					&window_pos);

			// We reset the cursor position to the middle of the window each frame
			m_win32_mouse.last_point.x = window_pos.left + (window_pos.right - window_pos.left) / 2;
			m_win32_mouse.last_point.y = window_pos.top + (window_pos.bottom - window_pos.top) / 2;

			SetCursorPos(m_win32_mouse.last_point.x, m_win32_mouse.last_point.y);
		}

		// update scroll axes
		m_mouse.lV = std::exchange(m_vscroll, 0) * input_device::RELATIVE_PER_PIXEL;
		m_mouse.lH = std::exchange(m_hscroll, 0) * input_device::RELATIVE_PER_PIXEL;
	}

	virtual void configure(input_device &device) override
	{
		// populate the axes
		device.add_item(
				"X",
				std::string_view(),
				ITEM_ID_XAXIS,
				generic_axis_get_state<LONG>,
				&m_mouse.lX);
		device.add_item(
				"Y",
				std::string_view(),
				ITEM_ID_YAXIS,
				generic_axis_get_state<LONG>,
				&m_mouse.lY);
		device.add_item(
				"Scroll V",
				std::string_view(),
				ITEM_ID_ZAXIS,
				generic_axis_get_state<LONG>,
				&m_mouse.lV);
		device.add_item(
				"Scroll H",
				std::string_view(),
				ITEM_ID_RZAXIS,
				generic_axis_get_state<LONG>,
				&m_mouse.lH);

		// populate the buttons
		for (int butnum = 0; butnum < 5; butnum++)
		{
			device.add_item(
					default_button_name(butnum),
					std::string_view(),
					input_item_id(ITEM_ID_BUTTON1 + butnum),
					generic_button_get_state<BYTE>,
					&m_mouse.rgbButtons[butnum]);
		}
	}

	virtual void reset() override
	{
		memset(&m_mouse, 0, sizeof(m_mouse));
		memset(&m_win32_mouse, 0, sizeof(m_win32_mouse));
		m_vscroll = m_hscroll = 0;
	}

protected:
	virtual void process_event(MouseUpdateEventArgs const &args) override
	{
		// set the button state
		assert(!(args.pressed & args.released));
		for (unsigned i = 0; 5 > i; ++i)
		{
			if (BIT(args.pressed, i))
				m_mouse.rgbButtons[i] = 0x80;
			else if (BIT(args.released, i))
				m_mouse.rgbButtons[i] = 0x00;
		}

		// accumulate scroll delta
		m_vscroll += args.vdelta;
		m_hscroll += args.hdelta;
	}

private:
	struct win32_mouse_state
	{
		POINT last_point;
	};

	mouse_state         m_mouse;
	win32_mouse_state   m_win32_mouse;
	long                m_vscroll, m_hscroll;
};


//============================================================
//  mouse_input_win32 - win32 mouse input module
//============================================================

class mouse_input_win32 : public wininput_module<win32_mouse_device>
{
public:
	mouse_input_win32() : wininput_module<win32_mouse_device>(OSD_MOUSEINPUT_PROVIDER, "win32")
	{
	}

	virtual void input_init(running_machine &machine) override
	{
		wininput_module<win32_mouse_device>::input_init(machine);

		if (!options()->mouse())
			return;

		// allocate a device
		create_device<win32_mouse_device>(DEVICE_CLASS_MOUSE, "Win32 Mouse 1", "Win32 Mouse 1");
	}

	virtual bool handle_input_event(input_event eventid, void *eventdata) override
	{
		if (manager().class_enabled(DEVICE_CLASS_MOUSE))
		{
			if ((eventid == INPUT_EVENT_MOUSE_BUTTON) || (eventid == INPUT_EVENT_MOUSE_WHEEL))
			{
				auto const *const args = reinterpret_cast<MouseUpdateEventArgs *>(eventdata);
				devicelist().for_each_device(
						[args] (auto &device) { device.queue_events(args, 1); });
				return true;
			}
		}

		return false;
	}
};


//============================================================
//  win32_lightgun_device_base
//============================================================

class win32_lightgun_device_base : public event_based_device<MouseUpdateEventArgs>
{
public:
	virtual void reset() override
	{
		memset(&m_mouse, 0, sizeof(m_mouse));
	}

protected:
	win32_lightgun_device_base(
			std::string &&name,
			std::string &&id,
			input_module &module) :
		event_based_device(std::move(name), std::move(id), module),
		m_mouse({ 0 })
	{
	}

	void do_configure(input_device &device, unsigned buttons)
	{
		// populate the axes
		for (int axisnum = 0; axisnum < 2; axisnum++)
		{
			device.add_item(
					default_axis_name[axisnum],
					std::string_view(),
					input_item_id(ITEM_ID_XAXIS + axisnum),
					generic_axis_get_state<LONG>,
					&m_mouse.lX + axisnum);
		}

		// populate the buttons
		for (int butnum = 0; butnum < buttons; butnum++)
		{
			device.add_item(
					default_button_name(butnum),
					std::string_view(),
					input_item_id(ITEM_ID_BUTTON1 + butnum),
					generic_button_get_state<BYTE>,
					&m_mouse.rgbButtons[butnum]);
		}
	}

	mouse_state m_mouse;
};



//============================================================
//  win32_lightgun_device
//============================================================

class win32_lightgun_device : public win32_lightgun_device_base
{
public:
	win32_lightgun_device(
			std::string &&name,
			std::string &&id,
			input_module &module) :
		win32_lightgun_device_base(std::move(name), std::move(id), module),
		m_vscroll(0),
		m_hscroll(0)
	{
	}

	virtual void poll(bool relative_reset) override
	{
		event_based_device::poll(relative_reset);

		int32_t xpos = 0, ypos = 0;

		// get the cursor position and transform into final results
		POINT mousepos;
		GetCursorPos(&mousepos);
		if (!osd_common_t::window_list().empty())
		{
			// get the position relative to the window
			HWND const hwnd = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window();
			RECT client_rect;
			GetClientRect(hwnd, &client_rect);
			ScreenToClient(hwnd, &mousepos);

			// convert to absolute coordinates
			xpos = normalize_absolute_axis(mousepos.x, client_rect.left, client_rect.right);
			ypos = normalize_absolute_axis(mousepos.y, client_rect.top, client_rect.bottom);
		}

		// update the X/Y positions
		m_mouse.lX = xpos;
		m_mouse.lY = ypos;

		// update the scroll axes if appropriate
		if (relative_reset)
		{
			m_mouse.lV = std::exchange(m_vscroll, 0) * input_device::RELATIVE_PER_PIXEL;
			m_mouse.lH = std::exchange(m_hscroll, 0) * input_device::RELATIVE_PER_PIXEL;
		}
	}

	virtual void configure(input_device &device) override
	{
		do_configure(device, 5);

		// add scroll axes
		device.add_item(
				"Scroll V",
				std::string_view(),
				ITEM_ID_ADD_RELATIVE1,
				generic_axis_get_state<LONG>,
				&m_mouse.lV);
		device.add_item(
				"Scroll H",
				std::string_view(),
				ITEM_ID_ADD_RELATIVE2,
				generic_axis_get_state<LONG>,
				&m_mouse.lH);
	}

	virtual void reset() override
	{
		win32_lightgun_device_base::reset();
		m_vscroll = m_hscroll = 0;
	}

protected:
	virtual void process_event(MouseUpdateEventArgs const &args) override
	{
		// In non-shared axis mode, just update the button state
		assert(!(args.pressed & args.released));
		for (unsigned i = 0; 5 > i; ++i)
		{
			if (BIT(args.pressed, i))
				m_mouse.rgbButtons[i] = 0x80;
			else if (BIT(args.released, i))
				m_mouse.rgbButtons[i] = 0x00;
		}

		// accumulate scroll delta
		m_vscroll += args.vdelta;
		m_hscroll += args.hdelta;
	}

private:
	long                m_vscroll, m_hscroll;
};


//============================================================
//  win32_dual_lightgun_device
//============================================================

class win32_dual_lightgun_device : public win32_lightgun_device_base
{
public:
	win32_dual_lightgun_device(
			std::string &&name,
			std::string &&id,
			input_module &module,
			int index) :
		win32_lightgun_device_base(std::move(name), std::move(id), module),
		m_gun_index(index)
	{
	}

	virtual void configure(input_device &device) override
	{
		do_configure(device, 2);
	}

protected:
	virtual void process_event(MouseUpdateEventArgs const &args) override
	{
		// We only handle the first four buttons in shared axis mode
		assert(!(args.pressed & args.released));
		for (unsigned i = 0; 2 > i; ++i)
		{
			// Adjust the button if we're the second lightgun
			unsigned const bit = i + ((1 == m_gun_index) ? 2 : 0);
			if (BIT(args.pressed, bit))
			{
				m_mouse.rgbButtons[i] = 0x80;

				// get the position relative to the window
				HWND const hwnd = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window();
				RECT client_rect;
				GetClientRect(hwnd, &client_rect);

				POINT mousepos;
				mousepos.x = args.xpos;
				mousepos.y = args.ypos;
				ScreenToClient(hwnd, &mousepos);

				// convert to absolute coordinates
				m_mouse.lX = normalize_absolute_axis(mousepos.x, client_rect.left, client_rect.right);
				m_mouse.lY = normalize_absolute_axis(mousepos.y, client_rect.top, client_rect.bottom);
			}
			else if (BIT(args.released, bit))
			{
				m_mouse.rgbButtons[i] = 0x00;
			}
		}
	}

private:
	int const m_gun_index;
};


//============================================================
//  lightgun_input_win32 - win32 lightgun input module
//============================================================

class lightgun_input_win32 : public wininput_module<win32_lightgun_device_base>
{
public:
	lightgun_input_win32() : wininput_module<win32_lightgun_device_base>(OSD_LIGHTGUNINPUT_PROVIDER, "win32")
	{
	}

	virtual void input_init(running_machine &machine) override
	{
		wininput_module<win32_lightgun_device_base>::input_init(machine);

		bool const shared_axis_mode = dynamic_cast<windows_options const &>(*options()).dual_lightgun();
		int const max_guns = shared_axis_mode ? 2 : 1;

		// allocate the lightgun devices
		for (int gunnum = 0; gunnum < max_guns; gunnum++)
		{
			static const char *const gun_names[] = { "Win32 Gun 1", "Win32 Gun 2" };

			// allocate a device
			if (shared_axis_mode)
				create_device<win32_dual_lightgun_device>(DEVICE_CLASS_LIGHTGUN, gun_names[gunnum], gun_names[gunnum], gunnum);
			else
				create_device<win32_lightgun_device>(DEVICE_CLASS_LIGHTGUN, gun_names[gunnum], gun_names[gunnum]);
		}
	}

	virtual bool handle_input_event(input_event eventid, void *eventdata) override
	{
		if (manager().class_enabled(DEVICE_CLASS_LIGHTGUN))
		{
			if ((eventid == INPUT_EVENT_MOUSE_BUTTON) || (eventid == INPUT_EVENT_MOUSE_WHEEL))
			{
				auto const *const args = reinterpret_cast<MouseUpdateEventArgs *>(eventdata);
				devicelist().for_each_device(
						[args] (auto &device) { device.queue_events(args, 1); });
				return true;
			}
		}

		return false;
	}
};

} // anonymous namespace

} // namespace osd

#else // defined(OSD_WINDOWS)

namespace osd {

namespace {

MODULE_NOT_SUPPORTED(keyboard_input_win32, OSD_KEYBOARDINPUT_PROVIDER, "win32")
MODULE_NOT_SUPPORTED(mouse_input_win32, OSD_MOUSEINPUT_PROVIDER, "win32")
MODULE_NOT_SUPPORTED(lightgun_input_win32, OSD_LIGHTGUNINPUT_PROVIDER, "win32")

} // anonymous namespace

} // namespace osd

#endif // defined(OSD_WINDOWS)

MODULE_DEFINITION(KEYBOARDINPUT_WIN32, osd::keyboard_input_win32)
MODULE_DEFINITION(MOUSEINPUT_WIN32, osd::mouse_input_win32)
MODULE_DEFINITION(LIGHTGUNINPUT_WIN32, osd::lightgun_input_win32)