タイトル | : Re: ホットキーの実装 |
記事No | : 16308 |
投稿日 | : 2017/05/20(Sat) 14:03 |
投稿者 | : 魔界の仮面弁士 |
> とある業務用アプリケーションをつかっています。 そのアプリは自作したものでしょうか。 それとも他者が作成したもので、自身では改修できないのでしょうか。
> また、vb6よりは.netのほうが簡単ということであれば > それでもいいです。 とりあえず、両方のパターンで回答しておきます。
> あるフィールドはマウスクリックでないと指定、選択できません。 そのフィールドは、UIAutomation で拾えますか? https://www.ka-net.org/blog/?p=4946
上記では PowerShell エクステンション版で紹介されていますが、 UI Automation の API 仕様に従い、自作アプリに同種の機構を組み込むこともできます。
あるいは昔ながらの MSAA で拾って IAccessible::accDoDefaultAction メソッドを呼び出すとか。
> findwindowや Declare Sub mouse_event Lib "user32" などで > 動作部分は完成したのですが、 既に実装済みなのですね。
他のアプリに対して Pause キーの押下をシミュレートする、という意味ならば、 SendInput API を使うことができるのではないでしょうか。この API は、 共用体配列を渡すことで、「Shift + 右クリック」のような、 キーボードとマウスの組み合わせ操作にも使えるようになっています。
----- VB6 ----- http://hanatyan.sakura.ne.jp/vb6/keyboard05.htm
----- VB.NET ----- http://hanatyan.sakura.ne.jp/vb2005/vb2013keyboard03.htm http://hanatyan.sakura.ne.jp/yybbs/read.cgi?mode=view&no=79
.NET 実装の場合は、下記の点にも留意しておください。 http://jinblog.at.webry.info/201604/article_1.html
> 本来の業務アプリケーションから起動することができません 「Pause キーが押されたとき」に何かアクションを起こしたいなら、 アクティブなフォームに対して、KeyDown イベントを仕掛けておくことができますが、 そのためには、「業務アプリ側」の改修が必要になってしまいますね。
---- VB6 ---- Option Explicit Friend Sub NoticePausePressed() List1.AddItem FormatDateTime(Now), 0 List1.NewIndex = 0 End Sub Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) If KeyCode = vbKeyPause Then NoticePausePressed End If End Sub Private Sub Form_Load() KeyPreview = True End Sub
---- VB.NET ---- Friend Sub NoticePausePressed() ListBox1.Items.Insert(0, Now) ListBox1.SelectedIndex = 0 Shell("notepad", AppWinStyle.NormalNoFocus, False) End Sub Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown If e.KeyCode = Keys.Pause Then NoticePausePressed() End If End Sub Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load KeyPreview = True End Sub
もしも自アプリがアクティブでない場合にもキー押下を拾いたい場合には、 DirectInput を使う方法や RegisterHotKey を使う方法などがあります。 今回は使う出番が無いかもしれませんが。
DirectInput で取得する方法については、下記に具体例があります。 (タイトルは「マウスジェスチャ」になっていますが、キー入力についても書かれています) http://www.geocities.co.jp/SiliconValley/7406/tips/mouse/index.html
ただ、今となっては、VB6 向けの dx8vb.dll (dx7vb.dll) は入手しにくくなっていますし、 .NET についても、Microsoft.DirectX.DirectInput.dll はサポートが終了しています。
DirectInput を使うのであれば、.NET から SharpDX (あるいは SlimDX)を 利用した方が良いかもしれません。
一方、RegisterHotKey についてはこんな感じです。 後者はホットキーのため、利用可能なキーの組み合わせに制限があります。
---- VB6 ---- http://www.geocities.co.jp/SiliconValley/4805/vbtips/vbtips092.htm ※VB6 では、WM_HOTKEY を捕らえるためにサブクラス化が必要なことに注意が必要です。 デバッグ時に「停止ボタン」で強制終了させるとクラッシュしてしまいますので、 必ず、Form_QueryUnload イベントの処理を通過させてから終了させるようにします。
---- VB.NET ---- Private Sub Form1_NoticeHotKey(sender As Object, e As HotKeyEventArgs) Handles Me.NoticeHotKey '自作イベント。今回は Pause キーが押されたときにここが実行されます。 End Sub
#Region "Pause キーをホットキーに割り当て" Public Event NoticeHotKey As EventHandler(Of HotKeyEventArgs) Private hotKeyAtom As String = "デファイアント"
Protected Overrides Sub OnHandleCreated(e As EventArgs) MyBase.OnHandleCreated(e) hotKeyId = GlobalAddAtom(hotKeyAtom) registered = RegisterHotKey(Handle, hotKeyId, ModifierFlags.None, Keys.Pause) End Sub
Private Const WM_HOTKEY As Integer = &H312 Protected Overrides Sub WndProc(ByRef m As Message) If m.Msg = WM_HOTKEY Then ' RaiseEvent NoticeHotKey(Me, New HotKeyEventArgs(m)) Else MyBase.WndProc(m) End If End Sub
Private Declare Unicode Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomW" (ByVal lpString As String) As UShort Private Declare Function GlobalDeleteAtom Lib "kernel32" (ByVal nAtom As UShort) As UShort Private Declare Function RegisterHotKey Lib "user32" (hWnd As IntPtr, id As Integer, fsModifiers As ModifierFlags, vk As Keys) As Boolean Private Declare Function UnregisterHotKey Lib "user32" (hWnd As IntPtr, id As Integer) As Boolean Private hotKeyId As UShort Private registered As Boolean Protected Overrides Sub OnFormClosing(e As FormClosingEventArgs) MyBase.OnFormClosing(e) If registered AndAlso UnregisterHotKey(Handle, hotKeyId) Then registered = False End If hotKeyId = GlobalDeleteAtom(hotKeyId) End Sub
<Flags> Private Enum ModifierFlags None = 0 Alt = 1 Control = 2 Shift = 4 Windows = 8 End Enum
Public Class HotKeyEventArgs Inherits KeyEventArgs Public Property Id As Integer Public Sub New(m As Message) MyBase.New(ToKeyData(m)) Id = CInt(m.WParam.ToInt64() And &HFFFFFFFF) End Sub Private Shared Function ToKeyData(m As Message) As Keys If m.Msg <> WM_HOTKEY Then Throw New ArgumentOutOfRangeException() End If 'KeyEventArgs.KeyData は、上位ワードが修飾キー、下位ワードがキーコードとなっているが、 'WM_HOTKEY の LPARAM は、上位ワードがキーコード、下位ワードが修飾キーなので入れ替える Dim modifierKeys As ModifierFlags = CType(m.LParam.ToInt64() And Keys.KeyCode, ModifierFlags) Dim keyCode As Keys = CType((m.LParam.ToInt64() And Keys.Modifiers) >> 16, Keys) Dim keyData As Keys = keyCode If (modifierKeys And ModifierFlags.Alt) = ModifierFlags.Alt Then keyData = keyData Or Keys.Alt If (modifierKeys And ModifierFlags.Shift) = ModifierFlags.Shift Then keyData = keyData Or Keys.Shift If (modifierKeys And ModifierFlags.Control) = ModifierFlags.Control Then keyData = keyData Or Keys.Control 'If (modifierKeys And ModifierFlags.Windows) = ModifierFlags.Windows Then keyData = keyData Return keyData End Function End Class #End Region
|