tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
[ツリー表示へ]  [ワード検索]  [Home]

タイトル Re: ホットキーの実装
投稿日: 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

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。