Неработающий сенсор закрытия крышки ноутбука и что из этого вышло

Какое-то время назад мой рабочий ноутбук отказался включаться. Просто не реагировал ни на какие попытки, включая отключение батареи. У технической поддержки ушло несколько месяцев на то, чтобы замененить практически все компоненты от матрицы до материнской платы и выяснить, что проблема была в перетертом шлейфе матрицы. Шлейф заменили, машина ожила и вернулась ко мне. Но в первый же день выяснилась интересная особенность — видимо, в пылу борьбы со шлейфом ремонтеры поломали или отключили датчик закрытия крышки. Теперь ноутбук не засыпает при закрытии крышки. Какое-то время я пытался найти способ устранить это самостоятельно, но в этот раз действенных советов Гугл и форумы комании Lenovo, к сожалению, не дали. Второй раз отдавать машину в ремонт просто страшно.

Ок, я не могу решить проблему механически, но может быть можно придумать, какой-то простой workaround. Например, я привык, уходя блокировать компьютер нажатием Win+L, почему бы не сделать shortcut для перевод машины в спящий режим? Выяснилось, что отправить машину в sleep несложно, но вот привязать это к нажатию на Ctrl+Q, например, уже не так тривиально. Можно найти софт, который будет управлять для вас этими функциями. Ну или написать свой. И так вышло, что как раз сегодня есть пара часов времени и стойкое желание попрактиковаться в программировании.

Так как программист я посредственный, то писать решил на C# в Visual Studio Community Edition. Чтобы не усложнять создал пустой проект в формате Windows Form Application с одной формой, в которую добавил контрол notifyIcon. Форму сделал невидимой сразу после старта, а в обработчк MouseDoubleClick добавил код включения и выключения видимости, чтобы форму можно было штатным образом закрыть. Эта мысль пришла не сразу, а после того, как стало понятно, что приложение должно уметь отменить регистрацию глобальных shortcut-ов после своей терминации.

Приложение добавлено в автозапуск и по нажатию на Ctrl+Q уверенно переводит машину в sleep. Не идеальное решение, но позволяет мириться с неработающим сенсором и несовершенством мира.
Может быть и вам эта поделка почему-то окажется полезной :)

Собственно код приложения тут:

using System;

namespace Sleep
{
    public partial class Form1 : Form
    {
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        enum KeyModifier
        {
            None = 0,
            Alt = 1,
            Control = 2,
            Shift = 4,
            WinKey = 8
        }

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            if (m.Msg == 0x0312)
            {
                // The key of the hotkey that was pressed.
                Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);
                // The modifier of the hotkey that was pressed.
                KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF);
                // The id of the hotkey that was pressed.
                int id = m.WParam.ToInt32();
                Application.SetSuspendState(PowerState.Suspend, true, true);
            }
        }

        public Form1()
        {
            InitializeComponent();
            int id = 0;
            RegisterHotKey(this.Handle, id, (int)KeyModifier.Control, Keys.Q.GetHashCode());
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            this.Visible = false;
        }

        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (this.Visible)
                this.Visible = false;
            else this.Visible = true;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            UnregisterHotKey(this.Handle, 0);
        }
    }
}
Метки:
coding4fun, C#, .net