mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -04:00
Merge branch 'release/1.10.x'
This commit is contained in:
commit
cbb3c182a5
@ -22,7 +22,7 @@ Installing Panda3D
|
||||
==================
|
||||
|
||||
The latest Panda3D SDK can be downloaded from
|
||||
[this page](https://www.panda3d.org/download/sdk-1-10-0/).
|
||||
[this page](https://www.panda3d.org/download/sdk-1-10-1/).
|
||||
If you are familiar with installing Python packages, you can use
|
||||
the following comand:
|
||||
|
||||
|
@ -100,8 +100,10 @@ class DirectScrolledFrame(DirectFrame):
|
||||
simpleChildGui = self.guiDict.get(parts[-1])
|
||||
if simpleChildGui:
|
||||
simpleChildGui.destroy()
|
||||
self.verticalScroll.destroy()
|
||||
self.horizontalScroll.destroy()
|
||||
del self.verticalScroll
|
||||
del self.horizontalScroll
|
||||
if self.verticalScroll:
|
||||
self.verticalScroll.destroy()
|
||||
if self.horizontalScroll:
|
||||
self.horizontalScroll.destroy()
|
||||
self.verticalScroll = None
|
||||
self.horizontalScroll = None
|
||||
DirectFrame.destroy(self)
|
||||
|
@ -96,22 +96,21 @@ class ParticlePanel(AppShell):
|
||||
|
||||
## MENUBAR ENTRIES ##
|
||||
# FILE MENU
|
||||
# Get a handle on the file menu so commands can be inserted
|
||||
# before quit item
|
||||
fileMenu = self.menuBar.component('File-menu')
|
||||
# MRM: Need to add load and save effects methods
|
||||
fileMenu.insert_command(
|
||||
fileMenu.index('Quit'),
|
||||
label = 'Load Params',
|
||||
command = self.loadParticleEffectFromFile)
|
||||
fileMenu.insert_command(
|
||||
fileMenu.index('Quit'),
|
||||
label = 'Save Params',
|
||||
command = self.saveParticleEffectToFile)
|
||||
fileMenu.insert_command(
|
||||
fileMenu.index('Quit'),
|
||||
label = 'Print Params',
|
||||
command = lambda s = self: s.particles.printParams())
|
||||
# Get a handle on the file menu, and delete the Quit item that AppShell
|
||||
# created so we can add it back after adding the other items.
|
||||
self.menuBar.deletemenuitems('File', 0, 0)
|
||||
self.menuBar.addmenuitem('File', 'command',
|
||||
label='Load Params',
|
||||
command=self.loadParticleEffectFromFile)
|
||||
self.menuBar.addmenuitem('File', 'command',
|
||||
label='Save Params',
|
||||
command=self.saveParticleEffectToFile)
|
||||
self.menuBar.addmenuitem('File', 'command',
|
||||
label='Print Params',
|
||||
command=lambda s=self:s.particles.printParams())
|
||||
self.menuBar.addmenuitem('File', 'command', 'Quit this application',
|
||||
label='Quit',
|
||||
command=self.quit)
|
||||
|
||||
# PARTICLE MANAGER MENU
|
||||
self.menuBar.addmenu('ParticleMgr', 'ParticleMgr Operations')
|
||||
|
@ -397,17 +397,25 @@ get_call_str(const string &container, const vector_string &pexprs) const {
|
||||
}
|
||||
|
||||
// It's not possible to assign arrays in C++, we have to copy them.
|
||||
CPPArrayType *array_type = _parameters[_first_true_parameter]._remap->get_orig_type()->as_array_type();
|
||||
bool paren_close = false;
|
||||
CPPType *param_type = _parameters[_first_true_parameter]._remap->get_orig_type();
|
||||
CPPArrayType *array_type = param_type->as_array_type();
|
||||
if (array_type != nullptr) {
|
||||
call << "std::copy(" << expr << ", " << expr << " + " << *array_type->_bounds << ", ";
|
||||
} else {
|
||||
paren_close = true;
|
||||
}
|
||||
else if (TypeManager::is_pointer_to_PyObject(param_type)) {
|
||||
call << "Dtool_Assign_PyObject(" << expr << ", ";
|
||||
paren_close = true;
|
||||
}
|
||||
else {
|
||||
call << expr << " = ";
|
||||
}
|
||||
|
||||
_parameters[_first_true_parameter]._remap->pass_parameter(call,
|
||||
get_parameter_expr(_first_true_parameter, pexprs));
|
||||
|
||||
if (array_type != nullptr) {
|
||||
if (paren_close) {
|
||||
call << ')';
|
||||
}
|
||||
|
||||
@ -772,6 +780,11 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
|
||||
_return_value_destructor = builder.get_destructor_for(return_meat_type);
|
||||
}
|
||||
|
||||
if (_type == T_getter && TypeManager::is_pointer_to_PyObject(return_type)) {
|
||||
_manage_reference_count = true;
|
||||
_return_value_needs_management = true;
|
||||
}
|
||||
|
||||
// Check for a special meaning by name and signature.
|
||||
size_t first_param = 0;
|
||||
if (_has_this) {
|
||||
|
@ -1690,7 +1690,6 @@ write_module_class(ostream &out, Object *obj) {
|
||||
SlottedFunctionDef def;
|
||||
def._answer_location = true_key;
|
||||
def._wrapper_type = slotted_def._wrapper_type;
|
||||
def._min_version = 0x03000000;
|
||||
def._wrapper_name = func->_name + "_" + true_key;
|
||||
slots[true_key] = def;
|
||||
}
|
||||
@ -5993,7 +5992,11 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
||||
indent(out, indent_level) << "}\n";
|
||||
}
|
||||
|
||||
return_expr = manage_return_value(out, indent_level, remap, "return_value");
|
||||
if (TypeManager::is_pointer_to_PyObject(remap->_return_type->get_orig_type())) {
|
||||
indent(out, indent_level) << "Py_XINCREF(return_value);\n";
|
||||
} else {
|
||||
return_expr = manage_return_value(out, indent_level, remap, "return_value");
|
||||
}
|
||||
return_expr = remap->_return_type->temporary_to_return(return_expr);
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,19 @@ INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, i
|
||||
Py_RETURN_RICHCOMPARE(cmpval, 0, op);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for assigning a PyObject pointer while managing refcounts.
|
||||
*/
|
||||
ALWAYS_INLINE void
|
||||
Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value) {
|
||||
PyObject *prev_value = ptr;
|
||||
if (prev_value != value) {
|
||||
Py_XINCREF(value);
|
||||
ptr = value;
|
||||
Py_XDECREF(prev_value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the enum value to a C long.
|
||||
*/
|
||||
|
@ -238,6 +238,8 @@ EXPCL_PYPANDA PyObject *_Dtool_Return(PyObject *value);
|
||||
#define Dtool_Return(value) _Dtool_Return(value)
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE void Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value);
|
||||
|
||||
/**
|
||||
* Wrapper around Python 3.4's enum library, which does not have a C API.
|
||||
*/
|
||||
|
@ -157,7 +157,7 @@ def usage(problem):
|
||||
print(" --everything (enable every third-party lib)")
|
||||
print(" --directx-sdk=X (specify version of DirectX SDK to use: jun2010, aug2009, mar2009, aug2006)")
|
||||
print(" --windows-sdk=X (specify Windows SDK version, eg. 7.0, 7.1 or 10. Default is 7.1)")
|
||||
print(" --msvc-version=X (specify Visual C++ version, eg. 10, 11, 12, 14. Default is 14)")
|
||||
print(" --msvc-version=X (specify Visual C++ version, eg. 10, 11, 12, 14, 14.1, 14.2. Default is 14)")
|
||||
print(" --use-icl (experimental setting to use an intel compiler instead of MSVC on Windows)")
|
||||
print("")
|
||||
print("The simplest way to compile panda is to just type:")
|
||||
|
@ -78,6 +78,7 @@ MSVCVERSIONINFO = {
|
||||
(12,0): {"vsversion":(12,0), "vsname":"Visual Studio 2013"},
|
||||
(14,0): {"vsversion":(14,0), "vsname":"Visual Studio 2015"},
|
||||
(14,1): {"vsversion":(15,0), "vsname":"Visual Studio 2017"},
|
||||
(14,2): {"vsversion":(16,0), "vsname":"Visual Studio 2019"},
|
||||
}
|
||||
|
||||
########################################################################
|
||||
|
@ -120,7 +120,7 @@ do_set_mass(PN_stdfloat mass) {
|
||||
btScalar bt_mass = mass;
|
||||
btVector3 bt_inertia(0.0, 0.0, 0.0);
|
||||
|
||||
if (bt_mass > 0.0) {
|
||||
if (bt_mass > 0.0 && !_shapes.empty()) {
|
||||
_rigid->getCollisionShape()->calculateLocalInertia(bt_mass, bt_inertia);
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ class BulletPersistentManifold;
|
||||
class BulletShape;
|
||||
class BulletSoftBodyWorldInfo;
|
||||
|
||||
extern PT(CallbackObject) bullet_contact_added_callback;
|
||||
extern EXPCL_PANDABULLET PT(CallbackObject) bullet_contact_added_callback;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -711,8 +711,11 @@ close_window() {
|
||||
}
|
||||
|
||||
if (_window != nil) {
|
||||
[_window setReleasedWhenClosed: YES];
|
||||
[_window close];
|
||||
|
||||
// Process events once more so any pending NSEvents are cleared. Not doing
|
||||
// this causes the window to stick around after calling [_window close].
|
||||
process_events();
|
||||
_window = nil;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,6 @@ class CocoaGraphicsWindow;
|
||||
- (void)windowDidBecomeKey:(NSNotification *)notification;
|
||||
- (void)windowDidResignKey:(NSNotification *)notification;
|
||||
- (BOOL)windowShouldClose:(id)sender;
|
||||
- (void)windowWillClose:(NSNotification *)notification;
|
||||
|
||||
// TODO: handle fullscreen on Lion.
|
||||
|
||||
|
@ -50,11 +50,11 @@
|
||||
}
|
||||
|
||||
- (BOOL) windowShouldClose:(id)sender {
|
||||
return _graphicsWindow->handle_close_request();
|
||||
}
|
||||
|
||||
- (void) windowWillClose:(NSNotification *)notification {
|
||||
_graphicsWindow->handle_close_event();
|
||||
bool should_close = _graphicsWindow->handle_close_request();
|
||||
if (should_close) {
|
||||
_graphicsWindow->handle_close_event();
|
||||
}
|
||||
return should_close;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -17,6 +17,22 @@
|
||||
|
||||
#if defined(_WIN32) && !defined(CPPPARSER)
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class InputThread : public Thread {
|
||||
public:
|
||||
InputThread(WinInputDeviceManager *manager) :
|
||||
Thread("input", "input"), _manager(manager) {}
|
||||
|
||||
private:
|
||||
virtual void thread_main();
|
||||
|
||||
WinInputDeviceManager *_manager;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initializes the input device manager by scanning which devices are currently
|
||||
* connected and setting up any platform-dependent structures necessary for
|
||||
@ -37,7 +53,7 @@ WinInputDeviceManager() :
|
||||
_xinput_device2.local_object();
|
||||
_xinput_device3.local_object();
|
||||
|
||||
// This function is only available in Vista and later, so we use a wrapper.
|
||||
// This function is only available in Vista and later, so we use a wrapper.
|
||||
HMODULE module = LoadLibraryA("cfgmgr32.dll");
|
||||
if (module) {
|
||||
_CM_Get_DevNode_PropertyW = (pCM_Get_DevNode_Property)GetProcAddress(module, "CM_Get_DevNode_PropertyW");
|
||||
@ -45,83 +61,16 @@ WinInputDeviceManager() :
|
||||
_CM_Get_DevNode_PropertyW = nullptr;
|
||||
}
|
||||
|
||||
// Now create a message-only window for the raw input.
|
||||
WNDCLASSEX wc = {};
|
||||
wc.cbSize = sizeof(WNDCLASSEX);
|
||||
wc.lpfnWndProc = window_proc;
|
||||
wc.hInstance = GetModuleHandle(nullptr);
|
||||
wc.lpszClassName = "InputDeviceManager";
|
||||
if (!RegisterClassEx(&wc)) {
|
||||
device_cat.warning()
|
||||
<< "Failed to register message-only window class.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
_message_hwnd = CreateWindowEx(0, wc.lpszClassName, "InputDeviceManager", 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
|
||||
if (!_message_hwnd) {
|
||||
device_cat.warning()
|
||||
<< "Failed to create message-only window.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Now listen for raw input devices using the created message loop.
|
||||
RAWINPUTDEVICE rid[3];
|
||||
rid[0].usUsagePage = 1;
|
||||
rid[0].usUsage = 4; // Joysticks
|
||||
rid[0].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
|
||||
rid[0].hwndTarget = _message_hwnd;
|
||||
rid[1].usUsagePage = 1;
|
||||
rid[1].usUsage = 5; // Gamepads
|
||||
rid[1].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
|
||||
rid[1].hwndTarget = _message_hwnd;
|
||||
rid[2].usUsagePage = 1;
|
||||
rid[2].usUsage = 8; // Multi-axis controllers (including 3D mice)
|
||||
rid[2].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
|
||||
rid[2].hwndTarget = _message_hwnd;
|
||||
if (!RegisterRawInputDevices(rid, 3, sizeof(RAWINPUTDEVICE))) {
|
||||
device_cat.warning()
|
||||
<< "Failed to register raw input devices.\n";
|
||||
}
|
||||
|
||||
// Do we have any XInput devices plugged in now?
|
||||
int num_xinput = 0;
|
||||
HANDLE xinput_handle;
|
||||
RAWINPUTDEVICELIST devices[64];
|
||||
UINT num_devices = 64;
|
||||
num_devices = GetRawInputDeviceList(devices, &num_devices, sizeof(RAWINPUTDEVICELIST));
|
||||
if (num_devices == (UINT)-1) {
|
||||
return;
|
||||
}
|
||||
for (UINT i = 0; i < num_devices; ++i) {
|
||||
if (devices[i].dwType != RIM_TYPEHID) {
|
||||
continue;
|
||||
}
|
||||
HANDLE handle = devices[i].hDevice;
|
||||
UINT size;
|
||||
if (GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, nullptr, &size) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char *path = (char *)alloca(size);
|
||||
if (path == nullptr ||
|
||||
GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, (void *)path, &size) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strstr(path, "&IG_") != nullptr) {
|
||||
xinput_handle = handle;
|
||||
++num_xinput;
|
||||
}
|
||||
}
|
||||
if (num_xinput == 1) {
|
||||
// There's only one XInput device, so we know which one it is.
|
||||
on_input_device_arrival(xinput_handle);
|
||||
} else if (num_xinput > 0) {
|
||||
// Just poll all the XInput devices.
|
||||
_xinput_device0.detect(this);
|
||||
_xinput_device1.detect(this);
|
||||
_xinput_device2.detect(this);
|
||||
_xinput_device3.detect(this);
|
||||
// If we have threading enabled, start a thread with a message-only window
|
||||
// loop to listen for input events.
|
||||
#ifdef HAVE_THREADS
|
||||
if (Thread::is_threading_supported()) {
|
||||
PT(Thread) thread = new InputThread(this);
|
||||
thread->start(TP_normal, false);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
setup_message_loop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,8 +80,17 @@ WinInputDeviceManager() :
|
||||
WinInputDeviceManager::
|
||||
~WinInputDeviceManager() {
|
||||
if (_message_hwnd != nullptr) {
|
||||
DestroyWindow(_message_hwnd);
|
||||
_message_hwnd = nullptr;
|
||||
#ifdef HAVE_THREADS
|
||||
if (Thread::is_threading_supported()) {
|
||||
HWND hwnd = _message_hwnd;
|
||||
if (hwnd) {
|
||||
SendMessage(hwnd, WM_QUIT, 0, 0);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
destroy_message_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -397,10 +355,110 @@ on_input_device_removal(HANDLE handle) {
|
||||
*/
|
||||
void WinInputDeviceManager::
|
||||
update() {
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, _message_hwnd, WM_INPUT_DEVICE_CHANGE, WM_INPUT, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a Windows message loop. Should be called from the thread that will
|
||||
* be handling the messages.
|
||||
*/
|
||||
HWND WinInputDeviceManager::
|
||||
setup_message_loop() {
|
||||
_message_hwnd = 0;
|
||||
|
||||
// Now create a message-only window for the raw input.
|
||||
WNDCLASSEX wc = {};
|
||||
wc.cbSize = sizeof(WNDCLASSEX);
|
||||
wc.lpfnWndProc = window_proc;
|
||||
wc.hInstance = GetModuleHandle(nullptr);
|
||||
wc.lpszClassName = "InputDeviceManager";
|
||||
if (!RegisterClassEx(&wc)) {
|
||||
device_cat.warning()
|
||||
<< "Failed to register message-only window class for input device detection.\n";
|
||||
} else {
|
||||
_message_hwnd = CreateWindowEx(0, wc.lpszClassName, "InputDeviceManager", 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
|
||||
if (!_message_hwnd) {
|
||||
device_cat.warning()
|
||||
<< "Failed to create message-only window for input device detection.\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Now listen for raw input devices using the created message loop.
|
||||
RAWINPUTDEVICE rid[3];
|
||||
rid[0].usUsagePage = 1;
|
||||
rid[0].usUsage = 4; // Joysticks
|
||||
rid[0].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
|
||||
rid[0].hwndTarget = _message_hwnd;
|
||||
rid[1].usUsagePage = 1;
|
||||
rid[1].usUsage = 5; // Gamepads
|
||||
rid[1].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
|
||||
rid[1].hwndTarget = _message_hwnd;
|
||||
rid[2].usUsagePage = 1;
|
||||
rid[2].usUsage = 8; // Multi-axis controllers (including 3D mice)
|
||||
rid[2].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
|
||||
rid[2].hwndTarget = _message_hwnd;
|
||||
if (!RegisterRawInputDevices(rid, 3, sizeof(RAWINPUTDEVICE))) {
|
||||
device_cat.warning()
|
||||
<< "Failed to register raw input devices.\n";
|
||||
}
|
||||
|
||||
// Do we have any XInput devices plugged in now?
|
||||
int num_xinput = 0;
|
||||
HANDLE xinput_handle;
|
||||
RAWINPUTDEVICELIST devices[64];
|
||||
UINT num_devices = 64;
|
||||
num_devices = GetRawInputDeviceList(devices, &num_devices, sizeof(RAWINPUTDEVICELIST));
|
||||
if (num_devices == (UINT)-1) {
|
||||
num_devices = 0;
|
||||
}
|
||||
for (UINT i = 0; i < num_devices; ++i) {
|
||||
if (devices[i].dwType != RIM_TYPEHID) {
|
||||
continue;
|
||||
}
|
||||
HANDLE handle = devices[i].hDevice;
|
||||
UINT size;
|
||||
if (GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, nullptr, &size) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char *path = (char *)alloca(size);
|
||||
if (path == nullptr ||
|
||||
GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, (void *)path, &size) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strstr(path, "&IG_") != nullptr) {
|
||||
xinput_handle = handle;
|
||||
++num_xinput;
|
||||
}
|
||||
}
|
||||
if (num_xinput == 1) {
|
||||
// There's only one XInput device, so we know which one it is.
|
||||
on_input_device_arrival(xinput_handle);
|
||||
} else if (num_xinput > 0) {
|
||||
// Just poll all the XInput devices.
|
||||
_xinput_device0.detect(this);
|
||||
_xinput_device1.detect(this);
|
||||
_xinput_device2.detect(this);
|
||||
_xinput_device3.detect(this);
|
||||
}
|
||||
|
||||
return _message_hwnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tears down the message loop. Should be called from the thread that called
|
||||
* setup_message_loop().
|
||||
*/
|
||||
void WinInputDeviceManager::
|
||||
destroy_message_loop() {
|
||||
HWND hwnd = nullptr;
|
||||
{
|
||||
LightMutexHolder holder(_lock);
|
||||
std::swap(_message_hwnd, hwnd);
|
||||
}
|
||||
|
||||
if (hwnd) {
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -442,4 +500,36 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
return DefWindowProcW(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
/**
|
||||
* Thread entry point for the input listener thread.
|
||||
*/
|
||||
void InputThread::
|
||||
thread_main() {
|
||||
WinInputDeviceManager *manager = _manager;
|
||||
HWND hwnd = manager->setup_message_loop();
|
||||
if (!hwnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (device_cat.is_debug()) {
|
||||
device_cat.debug()
|
||||
<< "Started input device listener thread.\n";
|
||||
}
|
||||
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, nullptr, 0, 0) > 0) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
if (device_cat.is_debug()) {
|
||||
device_cat.debug()
|
||||
<< "Stopping input device listener thread.\n";
|
||||
}
|
||||
|
||||
manager->destroy_message_loop();
|
||||
}
|
||||
#endif // HAVE_THREADS
|
||||
|
||||
#endif
|
||||
|
@ -41,6 +41,9 @@ public:
|
||||
void on_input_device_arrival(HANDLE handle);
|
||||
void on_input_device_removal(HANDLE handle);
|
||||
|
||||
HWND setup_message_loop();
|
||||
void destroy_message_loop();
|
||||
|
||||
private:
|
||||
// There are always exactly four of these in existence.
|
||||
XInputDevice _xinput_device0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user