Skip to content

Commit c53953a

Browse files
authored
Merge pull request #2 from Nat-Lab/leap
merge leap support to master
2 parents f452c6c + 513de76 commit c53953a

File tree

12 files changed

+472
-24
lines changed

12 files changed

+472
-24
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
build32
22
build64
3-
.vscode
3+
.vscode
4+
LeapSDK

3rdparty/README.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Download the Leap Motion Orion SDK package from https://developer.leapmotion.com and copy LeapSDK folder here.

chuniio/chuniio.c

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,32 @@
44
#include <fcntl.h>
55
#include <io.h>
66
#include "chuniio.h"
7+
#include "leapio/leapio.h"
78
#include "log.h"
89
#define CHUNI_WINPROC CallWindowProc(chuni_wndproc, hwnd, msg, w_param, l_param)
910
#define MAXFINGERS 10
1011
#define CONFIG L".\\chunitouch.ini"
1112

13+
#define CSRC_TOUCH 0
14+
#define CSRC_LEAP 1
15+
16+
#define LEAP_X 0
17+
#define LEAP_Y 1
18+
#define LEAP_Z 2
19+
1220
static LONG chuni_ir_trigger_threshold = 7000;
1321
static LONG chuni_ir_height = 5000;
22+
static UINT chuni_ir_leap_trigger = 500;
23+
static UINT chuni_ir_leap_step = 300;
24+
static uint8_t leap_orientation = LEAP_Y;
25+
1426
static LONG chuni_key_start = 31800;
1527
static LONG chuni_key_width = 4000;
1628

1729
static LONG chuni_key_end = 0; //chuni_key_start + 32 * chuni_key_width;
1830

1931
static bool raw_input = false;
32+
static uint8_t ir_control_source = CSRC_TOUCH;
2033
static bool ir_keep_slider = false;
2134

2235
static unsigned int __stdcall chuni_io_slider_thread_proc(void* ctx);
@@ -37,7 +50,9 @@ static int get_slider_from_pos(LONG x, LONG y) {
3750
return 31 - ((x - chuni_key_start) / chuni_key_width);
3851
}
3952

40-
static void chuni_io_ir(uint8_t *bitmap, uint8_t sensor_id, bool set) {
53+
static void chuni_io_ir(uint8_t *bitmap, int8_t sensor_id, bool set) {
54+
if (sensor_id > 5) sensor_id = 5;
55+
if (sensor_id < 0) sensor_id = 0;
4156
if (sensor_id % 2 == 0) sensor_id++;
4257
else sensor_id--;
4358
if (set) *bitmap |= 1 << sensor_id;
@@ -47,7 +62,7 @@ static void chuni_io_ir(uint8_t *bitmap, uint8_t sensor_id, bool set) {
4762
static int get_finger_index(DWORD id) {
4863
int avail_indx = -1;
4964
for (int i = 0; i < MAXFINGERS; i++) {
50-
if (finger_ids[i] == id) return i;
65+
if (finger_ids[i] > 0 && (DWORD) finger_ids[i] == id) return i;
5166
if (avail_indx == -1 && finger_ids[i] == -1) avail_indx = i;
5267
}
5368

@@ -86,13 +101,11 @@ LRESULT CALLBACK chuni_winproc_hook(HWND hwnd, UINT msg, WPARAM w_param, LPARAM
86101
if (!raw_input) ScreenToClient(hwnd, &local_point);
87102
if (p.dwFlags & TOUCHEVENTF_DOWN) start_locations[fid] = local_point.y;
88103
LONG x_diff = start_locations[fid] - local_point.y;
89-
if (x_diff > chuni_ir_trigger_threshold) {
90-
int ir_id = (x_diff / chuni_ir_height) - 1;
91-
if (ir_id > 5) ir_id = 5;
92-
if (ir_id < 0) ir_id = 0;
104+
if (ir_control_source == CSRC_TOUCH && x_diff > chuni_ir_trigger_threshold) {
105+
int8_t ir_id = (x_diff / chuni_ir_height) - 1;
93106
chuni_io_ir(&chuni_ir_map_local, ir_id, true);
94107
}
95-
if (x_diff <= chuni_ir_trigger_threshold || ir_keep_slider) {
108+
if (ir_control_source == CSRC_LEAP || x_diff <= chuni_ir_trigger_threshold || ir_keep_slider) {
96109
int slider_id = get_slider_from_pos(local_point.x, local_point.y);
97110
if (slider_id >= 0 && slider_id < 32) clicked_sliders[slider_id] = 128;
98111
}
@@ -106,6 +119,27 @@ LRESULT CALLBACK chuni_winproc_hook(HWND hwnd, UINT msg, WPARAM w_param, LPARAM
106119
return CHUNI_WINPROC;
107120
}
108121

122+
void leap_handler (const LEAP_TRACKING_EVENT *ev) {
123+
uint8_t chuni_ir_map_local = 0;
124+
125+
for(uint32_t h = 0; h < ev->nHands; h++) {
126+
const LEAP_HAND* hand = &(ev->pHands[h]);
127+
float pos = 0;
128+
if (leap_orientation == LEAP_X) pos = hand->palm.position.x;
129+
if (leap_orientation == LEAP_Y) pos = hand->palm.position.y;
130+
if (leap_orientation == LEAP_Z) pos = hand->palm.position.z;
131+
132+
if (pos > chuni_ir_leap_trigger) {
133+
int8_t ir_id = (pos - chuni_ir_leap_trigger) / chuni_ir_leap_step - 1;
134+
if (ir_id > 5) ir_id = 5;
135+
if (ir_id < 0) ir_id = 0;
136+
chuni_io_ir(&chuni_ir_map_local, ir_id, true);
137+
}
138+
}
139+
140+
chuni_ir_sensor_map = chuni_ir_map_local;
141+
}
142+
109143
HRESULT chuni_io_jvs_init(void) {
110144
// hook winproc
111145
HWND hwnd = FindWindowA(NULL, "teaGfx DirectX Release");
@@ -121,25 +155,58 @@ HRESULT chuni_io_jvs_init(void) {
121155
else {
122156
ULONG flags;
123157
if (!IsTouchWindow(hwnd, &flags)) log_warn("IsTouchWindow() returned false, touch might not work.\n");
158+
#ifdef _WIN64
159+
chuni_wndproc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)&chuni_winproc_hook);
160+
#else
124161
chuni_wndproc = (WNDPROC)SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)&chuni_winproc_hook);
162+
#endif
163+
125164
log_info("hooked WNDPROC.\n");
126165
}
127-
chuni_ir_height = GetPrivateProfileIntW(L"ir", L"height", 50, CONFIG) * 100;
128-
chuni_ir_trigger_threshold = GetPrivateProfileIntW(L"ir", L"trigger", 70, CONFIG) * 100;
166+
WCHAR str_control_src[16];
167+
WCHAR str_leap_orientation[16];
168+
169+
chuni_ir_height = GetPrivateProfileIntW(L"ir", L"touch_height", 50, CONFIG) * 100;
170+
chuni_ir_trigger_threshold = GetPrivateProfileIntW(L"ir", L"touch_trigger", 70, CONFIG) * 100;
171+
chuni_ir_leap_trigger = GetPrivateProfileIntW(L"ir", L"leap_trigger", 500, CONFIG);
172+
chuni_ir_leap_step = GetPrivateProfileIntW(L"ir", L"leap_step", 300, CONFIG);
129173
chuni_key_start = GetPrivateProfileIntW(L"slider", L"offset", 318, CONFIG) * 100;
130174
chuni_key_width = GetPrivateProfileIntW(L"slider", L"width", 40, CONFIG) * 100;
131175
raw_input = GetPrivateProfileIntW(L"io", L"raw_input", 0, CONFIG);
132176
ir_keep_slider = GetPrivateProfileIntW(L"misc", L"ir_keep_slider", 0, CONFIG);
133177

178+
GetPrivateProfileStringW(L"ir", L"control_source", L"touch", str_control_src, 16, CONFIG);
179+
GetPrivateProfileStringW(L"ir", L"leap_orientation", L"y", str_leap_orientation, 16, CONFIG);
180+
134181
chuni_key_end = chuni_key_start + 32 * chuni_key_width;
182+
ir_control_source = (wcscmp(str_control_src, L"leap") == 0) ? CSRC_LEAP : CSRC_TOUCH;
183+
/**/ if (wcscmp(str_leap_orientation, L"x") == 0) leap_orientation = LEAP_X;
184+
else if (wcscmp(str_leap_orientation, L"y") == 0) leap_orientation = LEAP_Y;
185+
else if (wcscmp(str_leap_orientation, L"z") == 0) leap_orientation = LEAP_Z;
135186

136187
for(int i = 0; i < MAXFINGERS; i++) finger_ids[i] = -1;
137188

189+
if (ir_control_source == CSRC_LEAP) {
190+
log_info("connecting to leap service...\n");
191+
leap_connect(NULL);
192+
leap_set_tracking_handler(leap_handler);
193+
while (!leap_is_connected()) {
194+
Sleep(10);
195+
}
196+
log_info("connected to leap service.\n");
197+
}
198+
199+
138200
log_info("raw_input: %s\n", raw_input ? "enabled" : "disabled");
139201
log_info("ir_keep_slider: %s\n", ir_keep_slider ? "enabled" : "disabled");
140-
log_info("ir: trigger_threshold: %ld, height: %ld\n", chuni_ir_trigger_threshold/100, chuni_ir_height/100);
141202
log_info("key: start: %ld, width: %ld, end: %ld\n", chuni_key_start/100, chuni_key_width/100, chuni_key_end/100);
142203

204+
if (ir_control_source == CSRC_TOUCH) {
205+
log_info("ir: touch mode, trigger_threshold: %ld, height: %ld\n", chuni_ir_trigger_threshold/100, chuni_ir_height/100);
206+
} else {
207+
log_info("ir: leap mode, axis: %u, trigger_threshold: %u, step: %u\n", leap_orientation, chuni_ir_leap_trigger, chuni_ir_leap_step);
208+
}
209+
143210
return S_OK;
144211
}
145212

chuniio/meson.build

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
chuniio_dll = shared_library(
22
'chuniio',
33
name_prefix : '',
4-
include_directories : inc,
4+
include_directories : [inc, leap_inc],
55
implicit_include_directories : false,
6-
vs_module_defs : 'chuniio.def',
76
c_pch : '../precompiled.h',
7+
link_with: [leapio_lib],
8+
dependencies: leap_lib,
9+
vs_module_defs : 'chuniio.def',
810
sources : [
911
'chuniio.c',
1012
'chuniio.h'
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include "leapio/leapio.h"
2+
#include "log.h"
3+
4+
void log_tracks(const LEAP_TRACKING_EVENT *ev) {
5+
log_debug("saw %u hands.\n", ev->nHands);
6+
for(uint32_t h = 0; h < ev->nHands; h++) {
7+
const LEAP_HAND* hand = &(ev->pHands[h]);
8+
log_debug("hand %u is a %s hand. location (%f, %f, %f).\n",
9+
hand->id, hand->type == eLeapHandType_Left ? "left" : "right",
10+
hand->palm.position.x, hand->palm.position.y, hand->palm.position.z);
11+
}
12+
}
13+
14+
int main () {
15+
log_info("connecting to leap service...\n");
16+
leap_set_tracking_handler(log_tracks); // debug
17+
18+
leap_connect(NULL);
19+
while (!leap_is_connected()) {
20+
Sleep(10);
21+
}
22+
log_info("connected to leap service.\n");
23+
24+
log_info("waiting for any leap device...\n");
25+
while (!leap_is_device_connected()) {
26+
Sleep(10);
27+
}
28+
log_info("leap device connected.\n");
29+
30+
leap_join_thread();
31+
32+
// TODO
33+
34+
log_info("disconnecting from leap service...\n");
35+
leap_disconnect();
36+
log_info("disconnected.\n");
37+
return 0;
38+
}
39+

leap-configurator/meson.build

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
leap_configurator = executable(
2+
'leapconfig',
3+
name_prefix : '',
4+
include_directories : [inc, leap_inc],
5+
implicit_include_directories : false,
6+
c_pch : '../precompiled.h',
7+
link_with: [leapio_lib],
8+
dependencies: leap_lib,
9+
sources : [
10+
'leap-configurator.c'
11+
]
12+
)

0 commit comments

Comments
 (0)