diff --git a/chuniio/chuniio.c b/chuniio/chuniio.c index 94bca2a..aab2361 100644 --- a/chuniio/chuniio.c +++ b/chuniio/chuniio.c @@ -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; @@ -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"; @@ -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; } } @@ -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); @@ -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); @@ -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; diff --git a/leap-configurator/leap-configurator.c b/leap-configurator/leap-configurator.c index c6af69a..4421e2c 100644 --- a/leap-configurator/leap-configurator.c +++ b/leap-configurator/leap-configurator.c @@ -1,18 +1,54 @@ +#include #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); } } @@ -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; @@ -45,8 +96,57 @@ 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() { @@ -54,11 +154,29 @@ void test() { 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()) { @@ -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"); diff --git a/leapio/leapio.c b/leapio/leapio.c index 38e65b6..4c46e3e 100644 --- a/leapio/leapio.c +++ b/leapio/leapio.c @@ -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; } } diff --git a/readme.md b/readme.md index 30cf068..f8ba98f 100644 --- a/readme.md +++ b/readme.md @@ -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