2008-01-10

Backキーのハンドルの仕方

Windows Mobile 6 Standardでアプリケーション開発をやり始めたんだけど、Backキーのハンドルがどうしてもできない。

しょうがないので、GoogleとかLive Searchで検索してみたところ、以下のドキュメントを発見

How to: Override the Smartphone Back Key

ふむふむ、Keys.EscapeとかKeys.Backをハンドルすればいいのか、、、と試しにやってみるが、上手くいかない。これって.NET Compact Framework 3.5じゃないと動かないの?ということで、いろいろ調べると、以下のところに落ち着いた

Capture Back Key - MSDN Forum

Mauricio,

This is a bug in CF. Setting the form's KeyPreview property to true should allow you to handle the Back key in the form's KeyPress event handler. However, I've discovered that the KeyPress event is only fired if the focused control is a container control (form, tab page, panel, etc.).

I'm investigating a couple of possible workarounds. I'll let you know if I find one.

Dan

ようはC#だとやり方がないということ。じゃ、ウィンドウプロシージャをのっとればいいじゃんと思ったが、.NET Compact Frameworkだと、ウィンドウプロシージャはFormクラスのメンバになってないそうだ。

やりたくはなかったが、サブクラス化して、ウィンドウメッセージを監視するしかないので、試してみたところ、以下のような感じでやれば、Backキーを監視、無効にすることは可能みたい。ホントはSHCMBM_OVERRIDEKEYを使うのがいい方法かと思うけど。

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowProc
{
    public partial class Form1 : Form
    {
        #region P/Invoke
        public const int GWL_WNDPROC = -4;
        public const uint WM_HOTKEY = 0x0312;

        [DllImport("coredll.dll")]
        public extern static IntPtr SetWindowLong(IntPtr hwnd,
                                                  int nIndex,
                                                  IntPtr dwNewLong);

        [DllImport("coredll.dll")]
        public extern static int CallWindowProc(IntPtr lpPrevWndFunc,
                                                IntPtr hwnd,
                                                uint msg,
                                                uint wParam,
                                                int lParam);

        [DllImport("coredll.dll")]
        public extern static int PostMessage(IntPtr hwnd,
                                             uint msg,
                                             uint wParam,
                                             uint lParam);
        #endregion

        public delegate int WndProcDelegate(IntPtr hwnd, uint msg, uint wParam, int lParam);

        IntPtr mOldWndProc;
        WndProcDelegate mProc;

        public Form1()
        {
            InitializeComponent();

            mProc = new WndProcDelegate(WndProc);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            SetHook();
        }

        private void SetHook()
        {
            IntPtr hwnd = this.Handle;
            if (hwnd == IntPtr.Zero)
            {
                throw new InvalidOperationException("hWnd is null");
            }

            mOldWndProc = SetWindowLong(hwnd,
                                        GWL_WNDPROC,
                                        Marshal.GetFunctionPointerForDelegate(mProc));
        }

        // Restores the original window procedure for the control.
        private void Unhook()
        {
            IntPtr hwnd = this.Handle;
            if (hwnd == IntPtr.Zero)
            {
                throw new InvalidOperationException("hWnd is null");
            }

            SetWindowLong(hwnd, GWL_WNDPROC, mOldWndProc);
        }

        protected virtual int WndProc(IntPtr hwnd, uint msg, uint wParam, int lParam)
        {
            if (msg == WM_HOTKEY && (lParam & 0xffff0000) == 0x1b0000)
            {
                if ((lParam & 0x1000) == 0)
                {
                    //
                    // This is key down message of [Back] key
                    //
                }
                return 1;
            }

            return CallWindowProc(mOldWndProc, hwnd, msg, wParam, lParam);
        }
    }
}

0 件のコメント: