Обновить

Комментарии 19

Ноутбук на винде, который гоняет пыль 99% просто в ожидании, занимает поверхность и т.д. — всё это прямо в духе DIY хабра последних лет. Когда писать статью не лень, а взять и изучить что-то более подходящее для этой задачи за это же время — ну нет. Пожилой человек, он же всё равно временно, не правда ли?

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

Видим непрошенный совет “взять и изучить что-то более подходящее для этой задачи за это же время”.

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

Автор взял и сделал рабочее решение, да ещё и выложил это в opensource на гитхаб. За что ему большое спасибо!

Я вот очень часто делаю очень странные решения, которые часто связывают вроде как несвязанные вещи (например, Firefox, видеомонтаж, PHP, Avisynth), но при этом решают задачи! И делаю так потому, что у меня мало времени, в самом широком смысле, я применяю те знания, которые уже имею, до тех пор, пока их хватает, потому что важнее не сделать “красиво как надо и получить пятерку”, а жить!

При этом постоянно находятся IT-шники-советчики, которые уверенно рассказывают, почему так нельзя и как надо. Смешно, что в реальной жизни их обычно об меня размазывает. Слишком колеблю картину мира при личном общении.

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

Что характерно, почти всегда заранее понятно, когда словлю минусов, но никогда непонятно, когда плюсов. Т.е. минусующие довольно предсказуемы.

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

И хабр, кстати говоря, тоже загадили. Не вижу совершенно никакого подвига в постинге такого мусора. Тем более по соседству с годными решениями, где люди постарались хоть немного. Потратили время и силы. Чтобы оказаться по соседству вот с этим вот…

Зря Вы так. Мне за код не стыдно. Там всего строк двести, но там есть и многопоточность, и перехват событий через 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;
}

глядел я на это и вспомнил что более 20 лет назад я делал вполне подобное. Была программа уже готовая типа "говорящие часы", у нее все .wav были в общих .dll с разными языками произношения, типа языковый плагин. Задача была просто подгрузить либу, но я тогда только учился winapi, интернета не было, но мне помогли оффлайн, и я просто использовал ее в своей наколенной разработке чисто под себя.

Всмысле? А что с ним не так, с качеством этого решения? Там 1 галка и один выпадающий список. Качество тут может определяться почти полярно - или это работает, или это не работает. Оно слишком простое, чтобы находиться где-то в середине и непредсказуемо глючить, как большинство современного софта.

Я не проверял (впрочем, как и вы), но предполагаю, что оно работает и не глючит, и поэтому у него скорее всего 100% качество.

И ещё не понимаю, как можно “загадить GitHub”. Это же не песочница и не двор, он бесконечный. Чем может помешать это решение, если оно честно делает именно то, что о нем рассказал автор?

как можно “загадить GitHub”. Это же не песочница и не двор

в целом то есть такое. если поиском скажем искать то куча конкретно мусорных репозиториев: 1 readme 0ой длины или "я здесь буду писать такой то проект" или какой то каркас без базового функционала, немало есть и костыльного и просто некрасивого кода. это приходится разгребать в поисках годного.

здесь же имеем по сути пример работы с WinApi каковых очень много еще со времен далеко до github. ничего плохого в этом нет, потеряет ли что то человечество без него - наверное тоже нет.

От этого комента пользы еще меньше, а вреда - гораздо больше.

По сути это пост, но на месте где можно 1) обозначить, "опубличить" проблему, в т.ч. перед людьми которые как бы их решают (например производителей часов и Алис) - бывает они тут тоже витают в облаках и статьи пишут 2) получить рекомендации по более эффектному решению с нужным срезом знаний

Автор взял и сделал рабочее решение, да ещё и выложил это в opensource на гитхаб. За что ему большое спасибо!

К сожалению это решение "рабочее" только когда автор этого решения находится в 5 минутах от этого ноутбука.

У меня так сильно удаленно работал ноутбук у родителей. Все было хорошо, но:

  • Сначала отказал тимвьюер, ибо санкции согласно его карте.

  • Потом сложился rdp/vnc потому как провайдер решил что белый(серый) айпи теперь за деньги.

  • А потом Виндовс решил обновится с 7 до 10 без лишних вопросов и админских прав. При этом выключив вай-фай, который включить можно только с правами.

У меня уже больше 5 лет удаленно работает комп: белый IP оплачен, RDP работает, Win 7 никуда не обновляется. Тут вопрос привычки и навыков.

И, вообще-то, автор выложил не свой ноутбук, а софт, который решает другую задачу. Зачем ему вообще доступ к этому компу? Настроил с утра и ушел, кнопка физически находится рядом с пользователем.

"Алиса, сколько времени?"

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

как вариант - home assistant, который по нажатию zigbee кнопки отправляет на яндекс станцию TTS запрос. первое что в голову пришло. возможно можно и проще

По-моему, проще всего найти готовые громкие говорящие часы, возможно - БУ.
Сталкивался такими, там чуть ли не во всей квартире было слышно: https://www.avito.ru/sankt-peterburg/chasy_i_ukrasheniya/govoryaschie_chasy_2000-2005_goda_izgotovleniya_8326390298

К сожалению, Алиса не разбирает тихий голос и речь после инсульта

как раз здесь есть ее разработчики - очень хороший повод их пинуть.

разработки умных устройств например SberDevices https://habr.com/ru/companies/yandex/ решают свои очень важные беспроводные проблемы https://habr.com/ru/companies/sberdevices/articles/1085744/ https://habr.com/ru/companies/yandex/articles/774212/ какие уж тут кнопки :) но наверное можно их спросить как решить вопрос тихого голоса

У меня при выключении холодильника висла клава. Сначала сделал ей кнопку reset, потом просто ферритовое кольцо на провод - помогло 100%.

А по поводу сложного решения простых задач - 1. работает из того, что есть под рукой, без лишних покупок и поисков. 2. работает - задача закрыта.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации