summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--platform/windows/detect.py11
-rw-r--r--platform/windows/os_windows.cpp50
-rw-r--r--platform/windows/os_windows.h7
-rw-r--r--platform/x11/detect.py9
-rw-r--r--platform/x11/os_x11.cpp160
-rw-r--r--platform/x11/os_x11.h11
6 files changed, 224 insertions, 24 deletions
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index fbb02c9d1b..890decf962 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -64,6 +64,10 @@ def get_opts():
return [
('mingw_prefix_32', 'MinGW prefix (Win32)', mingw32),
('mingw_prefix_64', 'MinGW prefix (Win64)', mingw64),
+ # Targeted Windows version: 7 (and later), minimum supported version
+ # XP support dropped after EOL due to missing API for IPv6 and other issues
+ # Vista support dropped after EOL due to GH-10243
+ ('target_win_version', 'Targeted Windows version, >= 0x0601 (Windows 7)', '0x0601'),
EnumVariable('debug_symbols', 'Add debug symbols to release version', 'yes', ('yes', 'no', 'full')),
]
@@ -97,11 +101,6 @@ def configure(env):
env.Append(CPPPATH=['#platform/windows'])
- # Targeted Windows version: 7 (and later), minimum supported version
- # XP support dropped after EOL due to missing API for IPv6 and other issues
- # Vista support dropped after EOL due to GH-10243
- winver = "0x0601"
-
if (os.name == "nt" and os.getenv("VCINSTALLDIR")): # MSVC
env['ENV']['TMP'] = os.environ['TMP']
@@ -175,7 +174,7 @@ def configure(env):
env.Append(CCFLAGS=['/DWASAPI_ENABLED'])
env.Append(CCFLAGS=['/DTYPED_METHOD_BIND'])
env.Append(CCFLAGS=['/DWIN32'])
- env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver])
+ env.Append(CCFLAGS=['/DWINVER=%s' % env['target_win_version'], '/D_WIN32_WINNT=%s' % env['target_win_version']])
if env["bits"] == "64":
env.Append(CCFLAGS=['/D_WIN64'])
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 9bcbb6ddb6..d62ecc6016 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -73,22 +73,17 @@ static String format_error_message(DWORD id) {
LPWSTR messageBuffer = NULL;
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
+ NULL, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
- String msg = "Error "+itos(id)+": "+String(messageBuffer,size);
+ String msg = "Error " + itos(id) + ": " + String(messageBuffer, size);
LocalFree(messageBuffer);
return msg;
-
}
-
-
extern HINSTANCE godot_hinstance;
-
-
void RedirectIOToConsole() {
int hConHandle;
@@ -228,7 +223,17 @@ bool OS_Windows::can_draw() const {
#define SIGNATURE_MASK 0xFFFFFF00
#define IsPenEvent(dw) (((dw)&SIGNATURE_MASK) == MI_WP_SIGNATURE)
-void OS_Windows::_touch_event(bool p_pressed, int p_x, int p_y, int idx) {
+void OS_Windows::_touch_event(bool p_pressed, float p_x, float p_y, int idx) {
+
+ // Defensive
+ if (touch_state.has(idx) == p_pressed)
+ return;
+
+ if (p_pressed) {
+ touch_state.insert(idx, Vector2(p_x, p_y));
+ } else {
+ touch_state.erase(idx);
+ }
Ref<InputEventScreenTouch> event;
event.instance();
@@ -241,7 +246,17 @@ void OS_Windows::_touch_event(bool p_pressed, int p_x, int p_y, int idx) {
}
};
-void OS_Windows::_drag_event(int p_x, int p_y, int idx) {
+void OS_Windows::_drag_event(float p_x, float p_y, int idx) {
+
+ Map<int, Vector2>::Element *curr = touch_state.find(idx);
+ // Defensive
+ if (!curr)
+ return;
+
+ if (curr->get() == Vector2(p_x, p_y))
+ return;
+
+ curr->get() = Vector2(p_x, p_y);
Ref<InputEventScreenDrag> event;
event.instance();
@@ -271,6 +286,13 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
ReleaseCapture();
}
+
+ // Release every touch to avoid sticky points
+ for (Map<int, Vector2>::Element *E = touch_state.front(); E; E = E->next()) {
+ _touch_event(false, E->get().x, E->get().y, E->key());
+ }
+ touch_state.clear();
+
break;
}
case WM_ACTIVATE: // Watch For Window Activate Message
@@ -674,7 +696,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
print_line("input lang change");
} break;
-#if WINVER >= 0x0601 // for windows 7
case WM_TOUCH: {
BOOL bHandled = FALSE;
@@ -687,10 +708,10 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
//do something with each touch input entry
if (ti.dwFlags & TOUCHEVENTF_MOVE) {
- _drag_event(ti.x / 100, ti.y / 100, ti.dwID);
+ _drag_event(ti.x / 100.0f, ti.y / 100.0f, ti.dwID);
} else if (ti.dwFlags & (TOUCHEVENTF_UP | TOUCHEVENTF_DOWN)) {
- _touch_event(ti.dwFlags & TOUCHEVENTF_DOWN != 0, ti.x / 100, ti.y / 100, ti.dwID);
+ _touch_event(ti.dwFlags & TOUCHEVENTF_DOWN, ti.x / 100.0f, ti.y / 100.0f, ti.dwID);
};
}
bHandled = TRUE;
@@ -708,7 +729,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
} break;
-#endif
case WM_DEVICECHANGE: {
joypad->probe_joypads();
@@ -1092,7 +1112,7 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
- //RegisterTouchWindow(hWnd, 0); // Windows 7
+ RegisterTouchWindow(hWnd, 0);
_ensure_user_data_dir();
@@ -1206,6 +1226,7 @@ void OS_Windows::finalize() {
memdelete(joypad);
memdelete(input);
+ touch_state.clear();
visual_server->finish();
memdelete(visual_server);
@@ -1608,7 +1629,6 @@ void OS_Windows::_update_window_style(bool repaint) {
Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
-
DLL_DIRECTORY_COOKIE cookie;
if (p_also_set_library_path) {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index e98f8277df..af1ccd4446 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -117,6 +117,7 @@ class OS_Windows : public OS {
InputDefault *input;
JoypadWindows *joypad;
+ Map<int, Vector2> touch_state;
PowerWindows *power_manager;
@@ -132,8 +133,8 @@ class OS_Windows : public OS {
CrashHandler crash_handler;
- void _drag_event(int p_x, int p_y, int idx);
- void _touch_event(bool p_pressed, int p_x, int p_y, int idx);
+ void _drag_event(float p_x, float p_y, int idx);
+ void _touch_event(bool p_pressed, float p_x, float p_y, int idx);
void _update_window_style(bool repaint = true);
@@ -212,7 +213,7 @@ public:
virtual void set_borderless_window(int p_borderless);
virtual bool get_borderless_window();
- virtual Error open_dynamic_library(const String p_path, void *&p_library_handle,bool p_also_set_library_path=false);
+ virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
virtual Error close_dynamic_library(void *p_library_handle);
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false);
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 3d07851c4f..d7dbe71da4 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -55,6 +55,7 @@ def get_opts():
BoolVariable('pulseaudio', 'Detect & use pulseaudio', True),
BoolVariable('udev', 'Use udev for gamepad connection callbacks', False),
EnumVariable('debug_symbols', 'Add debug symbols to release version', 'yes', ('yes', 'no', 'full')),
+ BoolVariable('touch', 'Enable touch events', True),
]
@@ -141,6 +142,14 @@ def configure(env):
env.ParseConfig('pkg-config xinerama --cflags --libs')
env.ParseConfig('pkg-config xrandr --cflags --libs')
+ if (env['touch']):
+ x11_error = os.system("pkg-config xi --modversion > /dev/null ")
+ if (x11_error):
+ print("xi not found.. cannot build with touch. Aborting.")
+ sys.exit(255)
+ env.ParseConfig('pkg-config xi --cflags --libs')
+ env.Append(CPPFLAGS=['-DTOUCH_ENABLED'])
+
# FIXME: Check for existence of the libs before parsing their flags with pkg-config
if not env['builtin_openssl']:
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index d1aa129e77..bf63921b06 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -178,6 +178,50 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
}
}
+#ifdef TOUCH_ENABLED
+ if (!XQueryExtension(x11_display, "XInputExtension", &touch.opcode, &event_base, &error_base)) {
+ fprintf(stderr, "XInput extension not available");
+ } else {
+ // 2.2 is the first release with multitouch
+ int xi_major = 2;
+ int xi_minor = 2;
+ if (XIQueryVersion(x11_display, &xi_major, &xi_minor) != Success) {
+ fprintf(stderr, "XInput 2.2 not available (server supports %d.%d)\n", xi_major, xi_minor);
+ touch.opcode = 0;
+ } else {
+ int dev_count;
+ XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count);
+
+ for (int i = 0; i < dev_count; i++) {
+ XIDeviceInfo *dev = &info[i];
+ if (!dev->enabled)
+ continue;
+ /*if (dev->use != XIMasterPointer)
+ continue;*/
+
+ bool direct_touch = false;
+ for (int j = 0; j < dev->num_classes; j++) {
+ if (dev->classes[j]->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) {
+ direct_touch = true;
+ printf("%d) %d %s\n", i, dev->attachment, dev->name);
+ break;
+ }
+ }
+ if (direct_touch) {
+ touch.devices.push_back(dev->deviceid);
+ fprintf(stderr, "Using touch device: %s\n", dev->name);
+ }
+ }
+
+ XIFreeDeviceInfo(info);
+
+ if (!touch.devices.size()) {
+ fprintf(stderr, "No suitable touch device found\n");
+ }
+ }
+ }
+#endif
+
xim = XOpenIM(x11_display, NULL, NULL, NULL);
if (xim == NULL) {
@@ -308,6 +352,32 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
XChangeWindowAttributes(x11_display, x11_window, CWEventMask, &new_attr);
+#ifdef TOUCH_ENABLED
+ if (touch.devices.size()) {
+
+ // Must be alive after this block
+ static unsigned char mask_data[XIMaskLen(XI_LASTEVENT)] = {};
+
+ touch.event_mask.deviceid = XIAllMasterDevices;
+ touch.event_mask.mask_len = sizeof(mask_data);
+ touch.event_mask.mask = mask_data;
+
+ XISetMask(touch.event_mask.mask, XI_TouchBegin);
+ XISetMask(touch.event_mask.mask, XI_TouchUpdate);
+ XISetMask(touch.event_mask.mask, XI_TouchEnd);
+ XISetMask(touch.event_mask.mask, XI_TouchOwnership);
+
+ XISelectEvents(x11_display, x11_window, &touch.event_mask, 1);
+
+ XIClearMask(touch.event_mask.mask, XI_TouchOwnership);
+
+ // Grab touch devices to avoid OS gesture interference
+ for (int i = 0; i < touch.devices.size(); ++i) {
+ XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask);
+ }
+ }
+#endif
+
/* set the titlebar name */
XStoreName(x11_display, x11_window, "Godot");
@@ -487,6 +557,10 @@ void OS_X11::finalize() {
#ifdef JOYDEV_ENABLED
memdelete(joypad);
#endif
+#ifdef TOUCH_ENABLED
+ touch.devices.clear();
+ touch.state.clear();
+#endif
memdelete(input);
visual_server->finish();
@@ -1435,6 +1509,69 @@ void OS_X11::process_xevents() {
continue;
}
+#ifdef TOUCH_ENABLED
+ if (XGetEventData(x11_display, &event.xcookie)) {
+
+ if (event.xcookie.extension == touch.opcode) {
+
+ XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
+ int index = event_data->detail;
+ Vector2 pos = Vector2(event_data->event_x, event_data->event_y);
+
+ switch (event_data->evtype) {
+
+ case XI_TouchBegin: // Fall-through
+ XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch);
+
+ case XI_TouchEnd: {
+
+ bool is_begin = event_data->evtype == XI_TouchBegin;
+
+ Ref<InputEventScreenTouch> st;
+ st.instance();
+ st->set_index(index);
+ st->set_position(pos);
+ st->set_pressed(is_begin);
+
+ if (is_begin) {
+ if (touch.state.has(index)) // Defensive
+ break;
+ touch.state[index] = pos;
+ input->parse_input_event(st);
+ } else {
+ if (!touch.state.has(index)) // Defensive
+ break;
+ touch.state.erase(index);
+ input->parse_input_event(st);
+ }
+ } break;
+
+ case XI_TouchUpdate: {
+
+ Map<int, Vector2>::Element *curr_pos_elem = touch.state.find(index);
+ if (!curr_pos_elem) { // Defensive
+ break;
+ }
+
+ if (curr_pos_elem->value() != pos) {
+
+ Ref<InputEventScreenDrag> sd;
+ sd.instance();
+ sd->set_index(index);
+ sd->set_position(pos);
+ sd->set_relative(pos - curr_pos_elem->value());
+ input->parse_input_event(sd);
+
+ curr_pos_elem->value() = pos;
+ }
+ } break;
+ }
+ }
+
+ XFreeEventData(x11_display, &event.xcookie);
+ }
+#endif
+
switch (event.type) {
case Expose:
Main::force_redraw();
@@ -1477,6 +1614,12 @@ void OS_X11::process_xevents() {
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime);
}
+#ifdef TOUCH_ENABLED
+ // Grab touch devices to avoid OS gesture interference
+ for (int i = 0; i < touch.devices.size(); ++i) {
+ XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask);
+ }
+#endif
if (xic) {
XSetICFocus(xic);
}
@@ -1493,6 +1636,23 @@ void OS_X11::process_xevents() {
}
XUngrabPointer(x11_display, CurrentTime);
}
+#ifdef TOUCH_ENABLED
+ // Ungrab touch devices so input works as usual while we are unfocused
+ for (int i = 0; i < touch.devices.size(); ++i) {
+ XIUngrabDevice(x11_display, touch.devices[i], CurrentTime);
+ }
+
+ // Release every pointer to avoid sticky points
+ for (Map<int, Vector2>::Element *E = touch.state.front(); E; E = E->next()) {
+
+ Ref<InputEventScreenTouch> st;
+ st.instance();
+ st->set_index(E->key());
+ st->set_position(E->get());
+ input->parse_input_event(st);
+ }
+ touch.state.clear();
+#endif
if (xic) {
XUnsetICFocus(xic);
}
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index a74e6ee5f3..84dff2e089 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -48,6 +48,9 @@
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
+#ifdef TOUCH_ENABLED
+#include <X11/extensions/XInput2.h>
+#endif
// Hints for X11 fullscreen
typedef struct {
@@ -117,6 +120,14 @@ class OS_X11 : public OS_Unix {
Point2i last_click_pos;
uint64_t last_click_ms;
uint32_t last_button_state;
+#ifdef TOUCH_ENABLED
+ struct {
+ int opcode;
+ Vector<int> devices;
+ XIEventMask event_mask;
+ Map<int, Vector2> state;
+ } touch;
+#endif
unsigned int get_mouse_button_state(unsigned int p_x11_state);
void get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state);