Skip to content

Commit

Permalink
Merge pull request #4 from Nat-Lab/separated-control
Browse files Browse the repository at this point in the history
improve leap controller
  • Loading branch information
magicnat authored Apr 11, 2020
2 parents d361dfa + c3a8129 commit 62be71f
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 25 deletions.
18 changes: 11 additions & 7 deletions chuniio/chuniio.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ static LONG chuni_ir_height = 5000;
static UINT chuni_ir_leap_trigger = 500;
static UINT chuni_ir_leap_step = 300;
static uint8_t leap_orientation = LEAP_Y;
static BOOL leap_inverted = FALSE;

static LONG chuni_key_start = 31800;
static LONG chuni_key_width = 4000;
Expand Down Expand Up @@ -156,7 +157,7 @@ static void make_control_window() {
D2D1_FACTORY_OPTIONS opt = { D2D1_DEBUG_LEVEL_INFORMATION };
if (D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &IID_ID2D1Factory, &opt, (void **) &d2df) != S_OK) {
log_fatal("can't create d2d factoy.\n");
// return?
return;
}
const char *name = "chuni-controller";

Expand Down Expand Up @@ -195,14 +196,14 @@ static void make_control_window() {

if (ID2D1Factory_CreateHwndRenderTarget(d2df, &rtp, &hrtp, &target) < 0) {
log_fatal("can't create d2d render target.\n");
// return
return;
}

for (int i = 0; i < 32; i++) {
D2D1_COLOR_F color = { i/32., i/32., i/32., 1. };
if (ID2D1HwndRenderTarget_CreateSolidColorBrush(target, &color, NULL, &brushes[i]) < 0) {
log_fatal("d2d brush creation failed.\n");
// return
return;
}
}

Expand All @@ -219,8 +220,8 @@ void leap_handler(const LEAP_TRACKING_EVENT *ev) {
if (leap_orientation == LEAP_Y) pos = hand->palm.position.y;
if (leap_orientation == LEAP_Z) pos = hand->palm.position.z;

if (pos > chuni_ir_leap_trigger) {
int8_t ir_id = (pos - chuni_ir_leap_trigger) / chuni_ir_leap_step - 1;
if ((!leap_inverted && pos > chuni_ir_leap_trigger) || (leap_inverted && chuni_ir_leap_trigger > pos)) {
int8_t ir_id = (leap_inverted ? -1 : 1) * (pos - chuni_ir_leap_trigger) / chuni_ir_leap_step + 1;
if (ir_id > 5) ir_id = 5;
if (ir_id < 0) ir_id = 0;
chuni_io_ir(&chuni_ir_map_local, ir_id, true);
Expand All @@ -247,8 +248,8 @@ HRESULT chuni_io_jvs_init(void) {
separate_control = GetPrivateProfileIntW(L"options", L"separate_control", FALSE, CONFIG);
chuni_ir_height = GetPrivateProfileIntW(L"ir", L"touch_height", 50, CONFIG);
chuni_ir_trigger_threshold = GetPrivateProfileIntW(L"ir", L"touch_trigger", 70, CONFIG);
chuni_ir_leap_trigger = GetPrivateProfileIntW(L"ir", L"leap_trigger", 500, CONFIG);
chuni_ir_leap_step = GetPrivateProfileIntW(L"ir", L"leap_step", 300, CONFIG);
chuni_ir_leap_trigger = GetPrivateProfileIntW(L"ir", L"leap_trigger", 50, CONFIG);
chuni_ir_leap_step = GetPrivateProfileIntW(L"ir", L"leap_step", 30, CONFIG);
chuni_key_start = GetPrivateProfileIntW(L"slider", L"offset", 318, CONFIG);
chuni_key_width = GetPrivateProfileIntW(L"slider", L"width", 40, CONFIG);
raw_input = GetPrivateProfileIntW(L"io", L"raw_input", 0, CONFIG);
Expand Down Expand Up @@ -280,6 +281,9 @@ HRESULT chuni_io_jvs_init(void) {
/**/ if (wcscmp(str_leap_orientation, L"x") == 0) leap_orientation = LEAP_X;
else if (wcscmp(str_leap_orientation, L"y") == 0) leap_orientation = LEAP_Y;
else if (wcscmp(str_leap_orientation, L"z") == 0) leap_orientation = LEAP_Z;
else if (wcscmp(str_leap_orientation, L"-x") == 0) { leap_orientation = LEAP_X; leap_inverted = TRUE; }
else if (wcscmp(str_leap_orientation, L"-y") == 0) { leap_orientation = LEAP_Y; leap_inverted = TRUE; }
else if (wcscmp(str_leap_orientation, L"-z") == 0) { leap_orientation = LEAP_Z; leap_inverted = TRUE; }

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

Expand Down
143 changes: 131 additions & 12 deletions leap-configurator/leap-configurator.c
Original file line number Diff line number Diff line change
@@ -1,18 +1,54 @@
#include <math.h>
#include "leapio/leapio.h"
#include "log.h"

static BOOL _test_mode = false;
#define CONFIG L".\\chunitouch.ini"

static BOOL _test_mode = FALSE;
static uint32_t _n_hands = 0;
float _x, _y, _z;
static float _x, _y, _z;
static BOOL use_leap;
static UINT leap_trigger;
static UINT leap_step;
static UINT leap_orientation;
static BOOL leap_inverted;

#define LEAP_X 0
#define LEAP_Y 1
#define LEAP_Z 2

void log_tracks(const LEAP_TRACKING_EVENT *ev) {
log_debug("saw %u hands.\n", ev->nHands);
void handle_track(const LEAP_TRACKING_EVENT *ev) {
// log_debug("saw %u hands.\n", ev->nHands);
static int8_t last_id = -1;
_n_hands = ev->nHands;
for(uint32_t h = 0; h < ev->nHands; h++) {
const LEAP_HAND* hand = &(ev->pHands[h]);
log_debug("hand %u is a %s hand. location (%f, %f, %f).\n",
hand->id, hand->type == eLeapHandType_Left ? "left" : "right",
hand->palm.position.x, hand->palm.position.y, hand->palm.position.z);
_x = hand->palm.position.x;
_y = hand->palm.position.y;
_z = hand->palm.position.z;

if (_test_mode) {
int8_t id = -1;
float pos = 0;
if (leap_orientation == LEAP_X) pos = _x;
if (leap_orientation == LEAP_Y) pos = _y;
if (leap_orientation == LEAP_Z) pos = _z;
if ((!leap_inverted && pos > leap_trigger) || (leap_inverted && leap_trigger > pos)) {
id = (leap_inverted ? -1 : 1) * (pos - leap_trigger) / leap_step - 1;
if (id > 5) id = 5;
if (id < 0) id = 0;
}

if (last_id != id) {
if (id >= 0) log_info("IR %d triggered.\n", id + 1);
else log_info("No IR triggered.\n");
last_id = id;
}
}

//log_debug("hand %u is a %s hand. location (%f, %f, %f).\n",
// hand->id, hand->type == eLeapHandType_Left ? "left" : "right",
// hand->palm.position.x, hand->palm.position.y, hand->palm.position.z);
}
}

Expand All @@ -32,11 +68,26 @@ char prompt(const char *p, const char *s, uint8_t n) {
}

void configure() {
bool low_ok = false, high_ok = false;
float low_x, low_y, low_z, high_x;
float low_x, low_y, low_z, high_x, high_y, high_z;

while (TRUE) {
prompt("Put your hand at the location you want the bottommost sensor to be activated, press [ENTER] when you are ready.", NULL, 0);
if (_n_hands == 0) {
printf("I can't see any hands.\n");
continue;
}
if (_n_hands > 1) {
printf("I saw more than one hand.\n");
continue;
}
low_x = _x;
low_y = _y;
low_z = _z;
break;
}

while (!low_ok) {
prompt("Put your hand at the lowest location you want the IR sensor to be triggered, then press [ENTER]", NULL, 0);
while (TRUE) {
prompt("Put your hand at the location you want the topmost sensor to be activated, press [ENTER] when you are ready.", NULL, 0);
if (_n_hands == 0) {
printf("I can't see any hands.\n");
continue;
Expand All @@ -45,20 +96,87 @@ void configure() {
printf("I saw more than one hand.\n");
continue;
}
high_x = _x;
high_y = _y;
high_z = _z;
break;
}

log_info("low: (%f, %f, %f), high: (%f, %f, %f).\n", low_x, low_y, low_z, high_x, high_y, high_z);
float dx = high_x - low_x;
float dy = high_y - low_y;
float dz = high_z - low_z;
float dmax = max(max(fabs(dx), fabs(dy)), fabs(dz));
WCHAR leap_orientation_char;

if (dmax == fabs(dx)) {
leap_orientation_char = 'x';
leap_orientation = LEAP_X;
leap_trigger = low_x;
}
if (dmax == fabs(dy)) {
leap_orientation_char = 'y';
leap_orientation = LEAP_Y;
leap_trigger = low_y;
}
if (dmax == fabs(dz)) {
leap_orientation_char = 'z';
leap_orientation = LEAP_Z;
leap_trigger = low_z;
}
if (leap_orientation == LEAP_X && dx < 0) {
leap_inverted = TRUE;
}
if (leap_orientation == LEAP_Y && dy < 0) {
leap_inverted = TRUE;
}
if (leap_orientation == LEAP_Z && dz < 0) {
leap_inverted = TRUE;
}
leap_step = dmax/6;
use_leap = TRUE;

WCHAR leap_trigger_str[16];
WCHAR leap_step_str[16];
WCHAR leap_orientation_str[16];

swprintf_s(leap_trigger_str, 16, L"%d", leap_trigger);
swprintf_s(leap_step_str, 16, L"%d", leap_step);
swprintf_s(leap_orientation_str, 16, L"%s%c", leap_inverted ? L"-" : L"", leap_orientation_char);

WritePrivateProfileStringW(L"ir", L"leap_trigger", leap_trigger_str, CONFIG);
WritePrivateProfileStringW(L"ir", L"leap_step", leap_step_str, CONFIG);
WritePrivateProfileStringW(L"ir", L"leap_orientation", leap_orientation_str, CONFIG);
}

void test() {
printf("Move your hand around. Configurator will print out which IR sensor is being activated.\n");
prompt("Press [ENTER] to begin test, press [ENTER] again to end.", NULL, 0);
_test_mode = true;
(void) getchar();
_test_mode = false;
}

int main () {
leap_trigger = GetPrivateProfileIntW(L"ir", L"leap_trigger", 50, CONFIG);
leap_step = GetPrivateProfileIntW(L"ir", L"leap_step", 30, CONFIG);

WCHAR str_control_src[16];
WCHAR str_leap_orientation[16];

GetPrivateProfileStringW(L"ir", L"control_source", L"touch", str_control_src, 16, CONFIG);
GetPrivateProfileStringW(L"ir", L"leap_orientation", L"y", str_leap_orientation, 16, CONFIG);
use_leap = wcscmp(str_control_src, L"leap") == 0;

/**/ if (wcscmp(str_leap_orientation, L"x") == 0) leap_orientation = LEAP_X;
else if (wcscmp(str_leap_orientation, L"y") == 0) leap_orientation = LEAP_Y;
else if (wcscmp(str_leap_orientation, L"z") == 0) leap_orientation = LEAP_Z;
else if (wcscmp(str_leap_orientation, L"-x") == 0) { leap_orientation = LEAP_X; leap_inverted = TRUE; }
else if (wcscmp(str_leap_orientation, L"-y") == 0) { leap_orientation = LEAP_Y; leap_inverted = TRUE; }
else if (wcscmp(str_leap_orientation, L"-z") == 0) { leap_orientation = LEAP_Z; leap_inverted = TRUE; }

log_info("connecting to leap service...\n");
leap_set_tracking_handler(log_tracks); // debug
leap_set_tracking_handler(handle_track); // debug

leap_connect(NULL);
while (!leap_is_connected()) {
Expand All @@ -68,6 +186,7 @@ int main () {

while (TRUE) {
printf("chuni-touch: leap configurator\n");
printf("current configured values: enabled: %s, trigger: %d, step: %d, orientation: %s%d.\n", use_leap ? "true" : "false", leap_trigger, leap_step, leap_inverted ? "-" : "", leap_orientation);
printf(" c) configure\n");
printf(" t) test\n");
printf("\n");
Expand Down
2 changes: 1 addition & 1 deletion leapio/leapio.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ static void leap_log(const LEAP_LOG_EVENT* e) {
case eLeapLogSeverity_Unknown: log_notice("%s.\n", e->message); break;
case eLeapLogSeverity_Critical: log_fatal("%s.\n", e->message); break;
case eLeapLogSeverity_Warning: log_warn("%s.\n", e->message); break;
case eLeapLogSeverity_Information: log_info("%s.\n", e->message); break;
// case eLeapLogSeverity_Information: log_info("%s.\n", e->message); break;
}
}

Expand Down
10 changes: 5 additions & 5 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ separate_control = 0
[ir]
; source of control. 'touch' for touchscreen and 'leap' for leap motion.
control_source = touch
; height of each touch IR sensor
; height of each touch IR sensor (unit: pixel)
touch_height = 50
; touch IR trigger threshold (number of pixels required to move up for a move to
; be registered as air)
touch_trigger = 70
; specifies the axis to track hands on. x, y, or z.
; specifies the axis to track hands on. x, y, z, -x, -y, or -z.
leap_orientation = y
; the minimum height of your hand(s) need to be for it to be registered as air
; (unit: millimeters)
leap_trigger = 500
leap_trigger = 100
; the height of each virtual IR sensor (unit: millimeters)
leap_step = 300
leap_step = 30
[slider]
; slider's width
; slider's width (unit: pixel)
width = 40
; slider's x-offset (pixels from the left of the screen)
offset = 318
Expand Down

0 comments on commit 62be71f

Please sign in to comment.