Обновить
4K+
54
Михаил Митрошин@MastaLomaster

временно неработающий

9,2
Рейтинг
32
Подписчики
Отправить сообщение

Олды вам скажут, что тру-сборка, это...

Ага, нашёл тут у себя недособранный компьютер...

Кавалеристы: — Вот это память у старика! (с)

Зря Вы так. Мне за код не стыдно. Там всего строк двести, но там есть и многопоточность, и перехват событий через SetWindowsHookEx. Код лаконичен, как и статья, но не обфусцирован, комментарии на месте. Привожу код ниже (убрал десяток закомментированных строк из того, что на гитхабе лежит).

Скрытый текст
#include <Windows.h>
#include "resource.h"
#include <process.h>

HHOOK handle;
volatile int sound_playing = 0;

wchar_t wbuffer[256];

int hour_iwillbeback(20); // час, когда я вернусь
int flag_iwillbeback = 0;

// имя файла со звуком, например, "пять часов утра..." для hours[5]
const wchar_t* hours[24] =
{
	L"h0.wav", L"h1.wav", L"h2.wav", L"h3.wav", L"h4.wav", L"h5.wav",
	L"h6.wav", L"h7.wav", L"h8.wav", L"h9.wav", L"h10.wav", L"h11.wav",
	L"h12.wav", L"h13.wav", L"h14.wav", L"h15.wav", L"h16.wav", L"h17.wav",
	L"h18.wav", L"h19.wav", L"h20.wav", L"h21.wav", L"h22.wav", L"h23.wav"
};

// единицы минут, например, "...восемь минут". "m0.wav" содержит слово "ровно". 
const wchar_t* mins[20] =
{
	L"m0.wav", L"m1.wav", L"m2.wav", L"m3.wav", L"m4.wav", L"m5.wav",
	L"m6.wav", L"m7.wav", L"m8.wav", L"m9.wav",
	L"m10.wav", L"m11.wav", L"m12.wav", L"m13.wav", L"m14.wav", L"m15.wav",
	L"m16.wav", L"m17.wav", L"m18.wav", L"m19.wav"
};

// десятки минут, например, "сорок".  
const wchar_t* mins10[4] =
{
	L"m20.wav", L"m30.wav", L"m40.wav", L"m50.wav"
};

//===================================================================
// Произносит часы и минуты из структуры SYSTEMTIME
//===================================================================
void PlayTime(SYSTEMTIME st)
{
	// ...надцать часов...
	PlaySound(hours[st.wHour], NULL, SND_FILENAME);

	if (st.wMinute < 20) // минуты в начале часа
	{
		PlaySound(mins[st.wMinute], NULL, SND_FILENAME);
	}
	else // от 20 до 59 минут
	{
		// Здесь сначала десятки минут
		PlaySound(mins10[st.wMinute / 10 - 2], NULL, SND_FILENAME);

		// теперь единицы минут, если они отличны от нуля
		if (st.wMinute % 10 != 0)
			PlaySound(mins[st.wMinute % 10], NULL, SND_FILENAME);
		else
			PlaySound(L"minut.wav", NULL, SND_FILENAME);
	}
}

//====================================================================================
// Поток для проигрывания звука
//====================================================================================
static volatile bool flag_shutdown_thread = false; // флаг информирует поток о том, что нужно выключиться
volatile HANDLE h_snd_event = NULL; // Событие с автосбросом
uintptr_t snd_thread_handle = NULL;

unsigned __stdcall FuncSndThread(void* p)
{
	while (true)
	{
		WaitForSingleObject(h_snd_event, INFINITE);
		// Это сигнал к продолжению или к завершению?
		if (flag_shutdown_thread) break;
		// Живём и играем!
		SYSTEMTIME st;
		GetLocalTime(&st); // Получает текущее локальное время

		// Московское время...
		PlaySound(L"mos_vremya.wav", NULL, SND_FILENAME);

		PlayTime(st);

		if (flag_iwillbeback)
		{
			PlaySound(L"iwillbeback.wav", NULL, SND_FILENAME);
			PlaySound(hours[hour_iwillbeback], NULL, SND_FILENAME);
		}
		
	}
	return 0;
}

//====================================================================================
// Перехватчик правой кнопки мыши в любом месте экрана 
//====================================================================================
LRESULT  CALLBACK HookProc(int disabled, WPARAM wParam, LPARAM lParam)
{
	if (!disabled)
	{
		MOUSEHOOKSTRUCT* pMouseStruct = (MOUSEHOOKSTRUCT*)lParam;
		if (pMouseStruct != NULL)
		{
			if (WM_RBUTTONDOWN == wParam)
			{
				//Beep(450,100); // Для отладки
				SetEvent(h_snd_event);
				return 1;
			}
			if (WM_RBUTTONUP == wParam) return 1;
		}
	}
	return CallNextHookEx(NULL, disabled, wParam, lParam);
}
				


//===================================================================
// Единственный диалог программы
//===================================================================
static BOOL CALLBACK DlgWndProc(HWND hdwnd,
	UINT uMsg,
	WPARAM wparam,
	LPARAM lparam)
{

	switch (uMsg)
	{
	case WM_COMMAND:
		switch (LOWORD(wparam))
		{
			case IDCANCEL: // Не случилось 
				EndDialog(hdwnd, 2);
				return 1;

			case IDOK: 
				// второй поток ждёт этого события
				SetEvent(h_snd_event);
				return 1;

			case IDC_COMBO_IWILLBEBACK:
				hour_iwillbeback = SendDlgItemMessage(hdwnd, IDC_COMBO_IWILLBEBACK, CB_GETCURSEL, 0, 0L);
				return 1;

			case IDC_CHECK_IWILLBEBACK:
				if (BST_CHECKED == SendDlgItemMessage(hdwnd, IDC_CHECK_IWILLBEBACK, BM_GETCHECK, 0, 0))
					flag_iwillbeback = 1;
				else
					flag_iwillbeback = 0;
				return 1;
					

		} // switch WM_COMMAND
		break; // if WM_COMMAND 

	case WM_INITDIALOG:
		SetWindowPos(hdwnd, HWND_TOP, 50, 50, 0, 0, SWP_NOSIZE | SWP_NOREDRAW);

		// заполняем часы в выпадающем списке
		for (int i = 0; i < 24; i++)
		{
			_itow_s(i, wbuffer, 10);
			SendDlgItemMessage(hdwnd, IDC_COMBO_IWILLBEBACK, CB_ADDSTRING, 0, (LPARAM)(wbuffer));
		}
		// по умолчанию вернусь в 20 часов
		SendDlgItemMessage(hdwnd, IDC_COMBO_IWILLBEBACK, CB_SETCURSEL, (WPARAM)hour_iwillbeback, 0);

		return 1; // Да, ставь фокус куда надо
		break;
	} // switch uMsg


	return 0;
}


//=======================================================================
// программа
//=======================================================================
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR cline, INT)
// Командную строку не обрабатываем
{
	// Запускаем поток, реагирующий на событие
	h_snd_event= CreateEvent(0, FALSE, FALSE, 0);
	snd_thread_handle = _beginthreadex(NULL, 0, FuncSndThread, 0, 0, NULL);
	
	// перехватываем нажатие на правую кнопку мыши во всей системе
	handle = SetWindowsHookEx(WH_MOUSE_LL,
		HookProc,
		GetModuleHandle(NULL),
		NULL);

	DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC)DlgWndProc);
	
	// перестаём реагировать на правую кнопку мыши	
	UnhookWindowsHookEx(handle);

	// Выключаем второй поток
	flag_shutdown_thread = true;
	SetEvent(h_snd_event);
	//  Для очистки совести дождёмся окончания потока?
	if (snd_thread_handle) WaitForSingleObject((HANDLE)snd_thread_handle, 0);
	CloseHandle(h_snd_event);

	return 0;
}

К сожалению, Алиса не разбирает тихий голос и речь после инсульта. А так - да, это мне сразу посоветовали. Если бы к ней можно было бы кнопку подключить на такой запрос - цены бы ей не было. Возможно, я просто не знаю, а возможность такая есть.

Понимаю Ваши возражения. Ждал, что мне скажут, что надо было всё делать на микроконтроллере. Но реальность такова, что старый нетбук валялся без дела, а написание программы заняло несколько часов. Time-to-market пересилило остальные аргументы.

Я имел в виду не просто раскладушку, а раскладушку с кнопками быстрого набора. Кроме того, представленный на фотографии телефон из прошлого имеет кнопку "SOS" на задней панели. Кнопка работает, даже когда раскладушка сложена.

В данном случае для звонка требуется сначала поднять телефонную трубку. В идеале, если бы она работала автономно, без связки с телефонным аппаратом, то, конечно, имело бы смысл делать на размыкание.

Спасибо за подсказку. Я даже нашёл б/у раскладушку с кнопками быстрого набора номера (М1, М2, М3). Б/у - потому что новых таких уже не делают. Но тактильно кнопки не выделяются, поэтому при плохом зрении не сильно помогают.

Благодарю, послушать - вполне достаточно.

Спасибо, интересно. Где можно скачать финальную (Suno) версию песни "Дубовый дом"?

Даже в своей статье Вы показываете результат не на реальном устройстве.

Нет-нет, все скриншоты программ получены на реальном телефоне одновременным нажатием кнопки питания и уменьшения громкости. Эмулятор вообще не использовался нигде.

У зайчика, да, каюсь, подставил готовую цветастую картинку, сам не стал изобретать.

Ну, за исключением одной маленькой детали: под капотом свой Linux со своими репозитариями, из которых можно хоть средства разработки поставить. Живёшь с маленьким линуксом в кармане.
К слову сказать, приложения андроида тоже можно запускать, но через эмулятор.

Мне кажется, речь шла исключительно про мягкий знак, то есть основы, а не неологизмы.
Можно ли будет где-нибудь приобрести печатную копию в книжном переплёте?
Мне кажется, жизнеспособным могло бы быть создание программных продуктов в университетских средах.

Когда изучение, например, виртуальной памяти иллюстрируется кодом своей же операционной системы, а план исполнения SQL-запроса описан в учебных пособиях.
Где курсовые проекты — написание или оптимизация существующего кода.
Где каждый новый студенческий курс модернизирует продукт. Весь код на виду, разработчики ровняются на стандарты, создаваемые в ведущих ВУЗах.

В книжных магазинах — курсы по операционным системам, СУБД, сетевым протоколам ссылаются на университетские образцы с открытыми исходными кодами.

Похоже на утопию, но примеры были. Например, в далёком 1970 — Berkley Ingres.
В теории надёжности устоявшимся термином является «высокая готовность», а не «высокая доступность».
Это, действительно, важно знать, спасибо.

Однако, когда я последний раз смотрел на то, что они сделали, программа была сыроватой:

— не было поддержки русской (кириллической) клавиатуры

— кнопки были маленькими, при нестабильном определении направления взгляда
пользоваться такой клавиатурой было крайне сложно:



Интересно сравнить с моей программой образца 2014 года: клавиши гигантские, есть режим увеличения куска клавиатуры, если трудно попасть взглядом в кнопку («клавиатура в 2 шага»), ну и ряд других тонкостей, которые появились, как ответ на замечания от реальных людей (например, режим «спать», когда парализованный человек устаёт от светящего на него экрана и хочет его сделать тёмным, но выключить его руками не может).

Забавно, что в справке к программе от Microsoft они написали фразу «Привет! Как дела?» (см. рисунок выше), прямо как писал я в давней статье, хотя русской клавиатуры у них нет.



Но ничто не стоит на месте, надеюсь, что доведут до ума.
Когда я начинал работу над этой программой, не было TobiiDynavox. Были отдельно Dynavox со своим EyeMax, и отдельно Tobii. А ещё были Sensomotoric Instruments, TheEyeTribe, LC Technologies, EyeTech, Gazepoint и другие. У всех было нечто для взаимодействия с компьютером. Идеи витали в воздухе, и все друг у друга их заимствовали. Так что вы найдёте много похожего в продуктах этих компаний, хоть некоторые из этих компаний уже не существуют. Из последних поглощений: TobiiDynavox поглощает Smartbox — производителя софта для рисования озвучиваемых таблиц на экране, вроде той, что я здесь описал, но с функционалом покруче.
Насколько мне известно, в современных трекерах светодиоды синхронизированы с кадровой развёрткой камеры: один кадр подсвечивается левым светодиодом, второй кадр — правым. Так проще разделять блики на зрачках. Плюс, обработка картинки (поиск зрачков, бликов на зрачках, вычисление углов, под которыми свет ИК-светодиодов падает на зрачки с учётом кривизны зрачка, измеренной при калибровке, отсечение бликов от очков и контактных линз) может осуществляться как в самом айтрекере (встроенным компьютером), так и быть возложено на компьютер, к которому он подключён. В этом трекере большая часть обработки происходит внутри, и компьютер сильно не нагружается.

Информация

В рейтинге
755-й
Откуда
Москва, Москва и Московская обл., Россия
Дата рождения
Зарегистрирован
Активность