summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/input/input_win32.cpp
blob: 0fb86095112540594b5c6b511a047ea459ecde4b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888 } /* Comment */
.highlight .err { color: #A61717; background-color: #E3D2D2 } /* Error */
.highlight .k { color: #080; font-weight: bold } /* Keyword */
.highlight .ch { color: #888 } /* Comment.Hashbang */
.highlight .cm { color: #888 } /* Comment.Multiline */
.highlight .cp { color: #C00; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888 } /* Comment.Single */
.highlight .cs { color: #C00; font-weight: bold; background-color: #FFF0F0 } /* Comment.Special */
.highlight .gd { color: #000; background-color: #FDD } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #A00 } /* Generic.Error */
.highlight .gh { color: #333 } /* Generic.Heading */
.highlight .gi { color: #000; background-color: #DFD } /* Generic.Inserted */
.highlight .go { color: #888 } /* Generic.Output */
.highlight .gp { color: #555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666 } /* Generic.Subheading */
.highlight .gt { color: #A00 } /* Generic.Traceback */
.highlight .kc { color: #080; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #080; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #080; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #080 } /* Keyword.Pseudo */
.highlight .kr { color: #080; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #00D; font-weight: bold } /* Literal.Number */
.highlight .s { color: #D20; background-color: #FFF0F0 } /* Literal.String */
.highlight .na { color: #369 } /* Name.Attribute */
.highlight .nb { color: #038 } /* Name.Builtin */
.highlight .nc { color: #B06; font-weight: bold } /* Name.Class */
.highlight .no { color: #036; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555 } /* Name.Decorator */
.highlight .ne { color: #B06; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #06B; font-weight: bold } /* Name.Function */
.highlight .nl { color: #369; font-style: italic } /* Name.Label */
.highlight .nn { color: #B06; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #369; font-weight: bold } /* Name.Property */
.highlight .nt { color: #B06; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #369 } /* Name.Variable */
.highlight .ow { color: #080 } /* Operator.Word */
.highlight .w { color: #BBB } /* Text.Whitespace */
.highlight .mb { color: #00D; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #00D; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #00D; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #00D; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #00D; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #D20; background-color: #FFF0F0 } /* Literal.String.Affix */
.highlight .sb { color: #D20; background-color: #FFF0F0 } /* Literal.String.Backtick */
.highlight .sc { color: #D20; background-color: #FFF0F0 } /* Literal.String.Char */
.highlight .dl { color: #D20; background-color: #FFF0F0 } /* Literal.String.Delimiter */
.highlight .sd { color: #D20; background-color: #FFF0F0 } /* Literal.String.Doc */
.highlight .s2 { color: #D20; background-color: #FFF0F0 } /* Literal.String.Double */
.highlight .se { color: #04D; background-color: #FFF0F0 } /* Literal.String.Escape */
.highlight .sh { color: #D20; background-color: #FFF0F0 } /* Literal.String.Heredoc */
.highlight .si { color: #33B; background-color: #FFF0F0 } /* Literal.String.Interpol */
.highlight .sx { color: #2B2; background-color: #F0FFF0 } /* Literal.String.Other */
.highlight .sr { color: #080; background-color: #FFF0FF } /* Literal.String.Regex */
.highlight .s1 { color: #D20; background-color: #FFF0F0 } /* Literal.String.Single */
.highlight .ss { color: #A60; background-color: #FFF0F0 } /* Literal.String.Symbol */
.highlight .bp { color: #038 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #06B; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #369 } /* Name.Variable.Class */
.highlight .vg { color: #D70 } /* Name.Variable.Global */
.highlight .vi { color: #33B } /* Name.Variable.Instance */
.highlight .vm { color: #369 } /* Name.Variable.Magic */
.highlight .il { color: #00D; font-weight: bold } /* Literal.Number.Integer.Long */
/*
  Simple DirectMedia Layer
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.
*/

/**
 *  \file SDL_touch.h
 *
 *  Include file for SDL touch event handling.
 */

#ifndef _SDL_touch_h
#define _SDL_touch_h

#include "SDL_stdinc.h"
#include "SDL_error.h"
#include "SDL_video.h"

#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif

typedef Sint64 SDL_TouchID;
typedef Sint64 SDL_FingerID;

typedef struct SDL_Finger
{
    SDL_FingerID id;
    float x;
    float y;
    float pressure;
} SDL_Finger;

/* Used as the device ID for mouse events simulated with touch input */
#define SDL_TOUCH_MOUSEID ((Uint32)-1)


/* Function prototypes */

/**
 *  \brief Get the number of registered touch devices.
 */
extern DECLSPEC int SDLCALL SDL_GetNumTouchDevices(void);

/**
 *  \brief Get the touch ID with the given index, or 0 if the index is invalid.
 */
extern DECLSPEC SDL_TouchID SDLCALL SDL_GetTouchDevice(int index);

/**
 *  \brief Get the number of active fingers for a given touch device.
 */
extern DECLSPEC int SDLCALL SDL_GetNumTouchFingers(SDL_TouchID touchID);

/**
 *  \brief Get the finger object of the given touch, with the given index.
 */
extern DECLSPEC SDL_Finger * SDLCALL SDL_GetTouchFinger(SDL_TouchID touchID, int index);

/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#include "close_code.h"

#endif /* _SDL_touch_h */

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

#include "input_module.h"
#include "modules/osdmodule.h"

#if defined(OSD_WINDOWS)
 
// standard windows headers
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winioctl.h>
#include <tchar.h>
#undef interface

#include <mutex>

// MAME headers
#include "emu.h"
#include "osdepend.h"
#include "ui/ui.h"
#include "strconv.h"

// MAMEOS headers
#include "winmain.h"
#include "window.h"

#include "input_common.h"
#include "input_windows.h"

//============================================================
//  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:
	keyboard_state keyboard;

	win32_keyboard_device(running_machine& machine, const char *name, input_module &module)
		: event_based_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
			keyboard({{0}})
	{
	}

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

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

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

class keyboard_input_win32 : public wininput_module
{
private:

public:
	keyboard_input_win32()
		: wininput_module(OSD_KEYBOARDINPUT_PROVIDER, "win32")
	{
	}

	virtual void input_init(running_machine &machine) override
	{
		// Add a single win32 keyboard device that we'll monitor using Win32
		win32_keyboard_device *devinfo = devicelist()->create_device<win32_keyboard_device>(machine, "Win32 Keyboard 1", *this);

		keyboard_trans_table &table = keyboard_trans_table::instance();

		// populate it
		for (int keynum = 0; keynum < MAX_KEYS; keynum++)
		{
			input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
			char name[20];

			// generate/fetch the name
			_snprintf(name, ARRAY_LENGTH(name), "Scan%03d", keynum);

			// add the item to the device
			devinfo->device()->add_item(name, itemid, generic_button_get_state, &devinfo->keyboard.state[keynum]);
		}
	}

	bool handle_input_event(input_event eventid, void *eventdata) override
	{
		if (!input_enabled())
			return FALSE;

		KeyPressEventArgs *args = nullptr;

		switch (eventid)
		{
			case INPUT_EVENT_KEYDOWN:
			case INPUT_EVENT_KEYUP:
				args = (KeyPressEventArgs*)eventdata;
				for (int i = 0; i < devicelist()->size(); i++)
					downcast<win32_keyboard_device*>(devicelist()->at(i))->queue_events(args, 1);

				return TRUE;

			default:
				return FALSE;
		}
	}
};

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

struct win32_mouse_state
{
	POINT last_point;
};

class win32_mouse_device : public event_based_device<MouseButtonEventArgs>
{
public:
	mouse_state			mouse;
	win32_mouse_state	win32_mouse;

	win32_mouse_device(running_machine& machine, const char *name, input_module &module)
		: event_based_device(machine, name, DEVICE_CLASS_MOUSE, module),
			mouse({0}),
			win32_mouse({{0}})
	{
	}

	void poll() override
	{
		event_based_device::poll();

		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
			mouse.lX = (cursor_info.ptScreenPos.x - win32_mouse.last_point.x) * INPUT_RELATIVE_PER_PIXEL;
			mouse.lY = (cursor_info.ptScreenPos.y - win32_mouse.last_point.y) * INPUT_RELATIVE_PER_PIXEL;

			RECT window_pos = {0};
			GetWindowRect(win_window_list->m_hwnd, &window_pos);

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

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

	void reset() override
	{
		memset(&mouse, 0, sizeof(mouse));
		memset(&win32_mouse, 0, sizeof(win32_mouse));
	}

protected:
	void process_event(MouseButtonEventArgs &args) override
	{
		// set the button state
		mouse.rgbButtons[args.button] = args.keydown ? 0x80 : 0x00;

		// Make sure we have a fresh mouse position on button down
		if (args.keydown)
			module().poll_if_necessary(machine());
	}
};

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

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

	virtual void input_init(running_machine &machine) override
	{
		win32_mouse_device *devinfo;
		int axisnum, butnum;

		if (!input_enabled() || !mouse_enabled())
			return;

		// allocate a device
		devinfo = devicelist()->create_device<win32_mouse_device>(machine, "Win32 Mouse 1", *this);
		if (devinfo == NULL)
			return;

		// populate the axes
		for (axisnum = 0; axisnum < 2; axisnum++)
		{
			devinfo->device()->add_item(default_axis_name[axisnum], (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.lX + axisnum);
		}

		// populate the buttons
		for (butnum = 0; butnum < 2; butnum++)
		{
			devinfo->device()->add_item(default_button_name(butnum), (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.rgbButtons[butnum]);
		}
	}

	bool handle_input_event(input_event eventid, void *eventdata) override
	{
		if (!input_enabled() || !mouse_enabled() || eventid != INPUT_EVENT_MOUSE_BUTTON)
			return FALSE;

		auto args = static_cast<MouseButtonEventArgs*>(eventdata);
		for (int i = 0; i < devicelist()->size(); i++)
			downcast<win32_mouse_device*>(devicelist()->at(i))->queue_events(args, 1);

		return TRUE;
	}
};

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

class win32_lightgun_device : public event_based_device<MouseButtonEventArgs>
{
private:
	BOOL m_lightgun_shared_axis_mode;
	int m_gun_index;

public:
	mouse_state		mouse;

	win32_lightgun_device(running_machine& machine, const char *name, input_module &module)
		: event_based_device(machine, name, DEVICE_CLASS_LIGHTGUN, module),
		  m_lightgun_shared_axis_mode(FALSE),
		  m_gun_index(0)
	{
		m_lightgun_shared_axis_mode = downcast<windows_options &>(machine.options()).dual_lightgun();

		// Since we are about to be added to the list, the current size is the zero-based index of where we will be
		m_gun_index = downcast<wininput_module&>(module).devicelist()->size();
	}

	void poll() override
	{
		event_based_device::poll();

		INT32 xpos = 0, ypos = 0;
		POINT mousepos;

		// if we are using the shared axis hack, the data is updated via Windows messages only
		if (m_lightgun_shared_axis_mode)
			return;

		// get the cursor position and transform into final results
		GetCursorPos(&mousepos);
		if (win_window_list != NULL)
		{
			RECT client_rect;

			// get the position relative to the window
			GetClientRect(win_window_list->m_hwnd, &client_rect);
			ScreenToClient(win_window_list->m_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
		mouse.lX = xpos;
		mouse.lY = ypos;
	}

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

protected:
	void process_event(MouseButtonEventArgs &args) override
	{
		// Are we in shared axis mode?
		if (m_lightgun_shared_axis_mode)
		{
			handle_shared_axis_mode(args);
		}
		else
		{
			// In non-shared axis mode, just update the button state
			mouse.rgbButtons[args.button] = args.keydown ? 0x80 : 0x00;
		}
	}

private:
	void handle_shared_axis_mode(MouseButtonEventArgs &args)
	{
		int button = args.button;

		// We only handle the first four buttons in shared axis mode
		if (button > 3)
			return;

		// First gun doesn't handle buttons 2 & 3
		if (button >= 2 && m_gun_index == 0)
			return;

		// Second gun doesn't handle buttons 0 & 1
		if (button < 2 && m_gun_index == 1)
			return;

		// Adjust the button if we're the second lightgun
		int logical_button = m_gun_index == 1 ? button - 2 : button;

		// set the button state
		mouse.rgbButtons[logical_button] = args.keydown ? 0x80 : 0x00;
		if (args.keydown)
		{
			RECT client_rect;
			POINT mousepos;

			// get the position relative to the window
			GetClientRect(win_window_list->m_hwnd, &client_rect);
			mousepos.x = args.xpos;
			mousepos.y = args.ypos;
			ScreenToClient(win_window_list->m_hwnd, &mousepos);

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

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

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

	int init_internal() override
	{
		return 0;
	}

	virtual void input_init(running_machine &machine) override
	{
		int max_guns = downcast<windows_options&>(machine.options()).dual_lightgun() ? 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" };
			win32_lightgun_device *devinfo;
			int axisnum, butnum;

			// allocate a device
			devinfo = devicelist()->create_device<win32_lightgun_device>(machine, gun_names[gunnum], *this);
			if (devinfo == NULL)
				break;

			// populate the axes
			for (axisnum = 0; axisnum < 2; axisnum++)
			{
				devinfo->device()->add_item(default_axis_name[axisnum], (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.lX + axisnum);
			}

			// populate the buttons
			for (butnum = 0; butnum < 2; butnum++)
			{
				devinfo->device()->add_item(default_button_name(butnum), (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.rgbButtons[butnum]);
			}
		}
	}

	bool handle_input_event(input_event eventid, void* eventdata) override
	{
		if (!input_enabled() || !lightgun_enabled() || eventid != INPUT_EVENT_MOUSE_BUTTON)
			return false;

		for (int i = 0; i < devicelist()->size(); i++)
			downcast<win32_lightgun_device*>(devicelist()->at(i))->queue_events(static_cast<MouseButtonEventArgs*>(eventdata), 1);

		return true;
	}
};

#else
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")
#endif

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