Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

Tata programista...

Praca na własny rachunek niesie ze sobą wiele korzyści. Jedną z nich jest możliwość częstszego przebywania bliżej rodziny (o ile takową posiadamy). Praca na własny rachunek w charakterze programisty nakłada obowiązek posiadania co najmniej jednego komputera, który współdzielimy (bądź nie) z pozostałymi domownikami. Jeżeli tymi domownikami są małe dzieci - oj, strzeżcie się pliki i foldery, albowiem wasze dni zostały policzone.

Sam mam dwójkę pociech, synka i córeczkę. Och, ach :) Synek, z racji swojego wieku (2,5 roku) i zawodu taty, szybko rozwinął grupę zdolności psychofizycznych umożliwiających sprawne poruszanie się po zakamarkach Internetu. Jeśli przez przypadek pozostawię myszkę "luzem", już po paru chwilach ze zdumieniem obserwuję "kota kota Fimejona" skaczącego po ekranie i Bonifacego wylegującego się na babcinym zapiecku... Pięć kliknięć myszką i YouTube gra pełną parą :) Niech mu będzie.

Swego czasu, na potrzeby świetego spokoju, wskazałem synkowi ikonę do TuxPainta. Wywołało to w nim falę niespotykanej dotąd radości, tym bardziej, że poza samym malowaniem, program oferuje możliwość umieszczania na obrazkach tekstu. Klawiaturę opanował błyskawicznie. Tym większe było moje zdziwienie, kiedy synek, z "chronionego", pełnoekranowego trybu "Dla dzieci", powracał do Pulpitu - bo mu się malowanie znudziło - i rozpoczynał fragmentację moich programistycznych projektów. Ech...

r   e   k   l   a   m   a

Tylko dla wybranych (klawiszy...)

Ostatnio natrafiłem na stronę www.virtualpiano.net i zaprezentowałem znalezisko małemu psotnikowi. Zabawa niesłychana! Z tym, że gra na wirtualnym pianinie odbywa się za pomocą wybranych - a nie WSZYSTKICH klawiszy :P. Hmm, ale przecież tata zajmuje się tym czym zajmuje. Wziąłem więc synka na kolana i razem zabraliśmy się za pisanie "oprogramowania pomocniczego". Porady malucha były na tyle owocne, że już po kilkunastu minutach klawiatura została okiełznana, a program ukończony (kliknij tutaj, aby pobrać program).

Aplikacja wymaga .NET Framework 2.0 (Systemy Windows Vista i wyżej posiadają środowisko uruchomieniowe .NET w odpowiedniej wersji). Program blokuje przetwarzanie przez system operacyjny tych klawiszy, które nie znajdują się na "białej liście" (w uproszczeniu, ponieważ nie jest to do końca prawda). Jeśli do tego ukryjemy myszkę w sejfie, to możemy pozwolić naszym dzieciom na odrobinę zabawy z wykorzystaniem sprzętu komputerowego, bez konieczności nieustannego zerkania przez ramię.

Efekt końcowy jak na załączonym obrazku :)

Uwaga! Dzieci nie powinny spędzać przy komputerze dłużej niż 20 minut dziennie.

* w ofercie posiadam także inne programistyczne wynalazki dla rodziców małych pociech ;)

Poniżej załączam kod źródłowy (w wersji "wyścig z czasem"). Klasa InterceptKeys to zmodyfikowana implementacja mechanizmu haków w .NET Stephena Toub'a (http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx ).


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace PreventKeys
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new FormKeys());
        }
    }

    public class FormKeys : Form
    {
        Button buttonPreventKeys;

        public FormKeys()
        {
            this.Text = "Klawiatura dla psotnika";
            this.StartPosition = FormStartPosition.CenterScreen;
            this.Size = new System.Drawing.Size(480, 150);

            RichTextBox allowableKeysRichTextBox = new RichTextBox();
            allowableKeysRichTextBox.BorderStyle = BorderStyle.None;
            allowableKeysRichTextBox.BackColor = System.Drawing.Color.White;
            allowableKeysRichTextBox.ReadOnly = true;
            allowableKeysRichTextBox.Dock = DockStyle.Fill;

            InterceptKeys.AllowableKeysRichTextBox = allowableKeysRichTextBox;

            allowableKeysRichTextBox.GotFocus += new EventHandler(allowableKeysRichTextBox_GotFocus);
            allowableKeysRichTextBox.LostFocus += new EventHandler(allowableKeysRichTextBox_LostFocus);

            buttonPreventKeys = new Button();
            buttonPreventKeys.Text = "Zablokuj pozostałe klawisze";
            buttonPreventKeys.Dock = DockStyle.Bottom;
            buttonPreventKeys.Click += new EventHandler(buttonPreventKeys_Click);

            Label label = new Label();
            label.Text = "Kliknij myszką na poniższym polu i naciśnij klawisze, które mają być dostępne dla dziecka";
            label.AutoSize = true;
            label.Padding = new System.Windows.Forms.Padding(4);
            label.Dock = DockStyle.Top;

            this.Controls.Add(allowableKeysRichTextBox);
            this.Controls.Add(label);
            this.Controls.Add(buttonPreventKeys);

            Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
        }

        void allowableKeysRichTextBox_LostFocus(object sender, EventArgs e)
        {
            InterceptKeys.UnHook();
            InterceptKeys.HookMode = InterceptKeys.Mode.PreventOtherKeys;
        }

        void allowableKeysRichTextBox_GotFocus(object sender, EventArgs e)
        {
            buttonPreventKeys.Text = "Zablokuj pozostałe klawisze";
            buttonPreventKeys.Tag = null;
            InterceptKeys.UnHook();

            InterceptKeys.HookMode = InterceptKeys.Mode.PrepareAllowableKeys;
            InterceptKeys.Hook();
        }

        void buttonPreventKeys_Click(object sender, EventArgs e)
        {
            Button button = sender as Button;

            if (button.Tag == null)
            { 
                InterceptKeys.Hook();
                button.Text = "Odblokuj wszystkie klawisze";
                button.Tag = true;
            }
            else
            {
                InterceptKeys.UnHook();
                button.Text = "Zablokuj pozostałe klawisze";
                button.Tag = null;
            }
        }

        void Application_ApplicationExit(object sender, EventArgs e)
        {
            InterceptKeys.UnHook();
        }
    }

    public static class InterceptKeys
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private static LowLevelKeyboardProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;
        private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

        public enum Mode
        {
            PrepareAllowableKeys,
            PreventOtherKeys
        }

        public static Mode HookMode { get; set; }
        public static RichTextBox AllowableKeysRichTextBox { get; set; }

        public static void Hook()
        {
            _hookID = SetHook(_proc);
        }

        public static void UnHook()
        {
            UnhookWindowsHookEx(_hookID);
        }

        private static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);

                string keyName = Enum.GetName(typeof(Keys), vkCode);
                bool found = false;

                // Uuuu, ale nieefektywny sposób :)
                // A ile pamięci marnujemy... Dobrze, że GC działa jak należy...
                // Nie ma czasu na zabawę w wyrażenia regularne...
                string[] split = AllowableKeysRichTextBox.Text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                for (int j = 0; j < split.Length; ++j)
                {
                    if (split[j] == keyName)
                    {
                        found = true;
                        break;
                    }
                }

                if (HookMode == Mode.PrepareAllowableKeys)
                {
                    if (!found)
                        AllowableKeysRichTextBox.Text += String.Format("{0} ", keyName);
                    else
                        return new IntPtr(1);
                }
                else
                {
                    if (found)
                        return CallNextHookEx(_hookID, nCode, wParam, lParam);
                    else
                        return new IntPtr(1);
                }
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);
    }
}

 

windows oprogramowanie programowanie

Komentarze