• ベストアンサー

VBAでCTRLキーが押されるまで処理を待つには

ExcelのVBAの処理で、処理結果を画面表示した後、 ユーザーが画面の内容を確認したら CTRLキーを押すと、 次の処理を続行するようにしたいのですが、 メッセージボックス(MSGBOX)などは表示しないで、 (画面表示内容以外のものは表示しないで) 処理を一時停止させて、CTRLキーが押されたら続行するには、 VBAでどのように記述すればよいでしょうか。 よろしくお願いします。(Windows10,Excel2016)

質問者が選んだベストアンサー

  • ベストアンサー
  • HohoPapa
  • ベストアンサー率65% (455/693)
回答No.2

他の方のコメントにもありますように、 一般的には採用しないインターフェースとは思いますが 時間もあり、興味を惹かれたので書いてみました。 よかったら参考にしてください。 なお、このコードはCntlキーが押されたかどうかではなく Cntlキーが押された状態か?を10ミリ秒間隔で監視することで実現していますので 10ミリ秒以上押し続ける必要があります。 実際に使ってみると、当方の環境では、 Cntlキーが押されたかどうかを判断しているがごとき動作をし、 違和感はありません。 また、Officeは32ビット版限定のコードです。 Option Explicit '参考url '  https://thom.hateblo.jp/entry/2019/03/10/125326 '  https://e-vba.com/keycode/ '//- API  ----------------------------- Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long) #If Win64 Then  Declare PtrSafe Function GetAsyncKeyState Lib _    "User32.dll" (ByVal vKey As LongLong) As Integer #Else  #If VBA6 Or VBA5 Then   Declare Function GetAsyncKeyState Lib _     "User32.dll" (ByVal vKey As Long) As Integer  #Else   Declare PtrSafe Function GetAsyncKeyState Lib _     "User32.dll" (ByVal vKey As Long) As Integer  #End If #End If '//----------サンプルコード Sub test()  '何らかの処理    PauseCntl    '何らかの処理 End Sub '//------ 'Cntlキーが押されるまで待つ関数 Sub PauseCntl()  Do   If IsShiftKeyPressed = True Then Exit Sub   Sleep 10   DoEvents  Loop End Sub Function IsShiftKeyPressed() As Boolean   Const KEY_PRESSED = -32768   '1000 0000 0000 0000 最上位ビットが1であることを示す。   IsShiftKeyPressed = (GetAsyncKeyState(vbKeyControl) And KEY_PRESSED) = KEY_PRESSED End Function

ID_20150222
質問者

お礼

教えていただきましたコードの動作を確認しました。 Excelアプリケーション画面を最小化した状態でも、 CTRLキーを押すまで停止していて、 CTRLキーが押されると続行されました。 挙動自体もまったく違和感はなく問題ありませんでした。 ありがとうございました。

その他の回答 (2)

  • imogasi
  • ベストアンサー率27% (4737/17070)
回答No.3

小生はAPIを使うべき課題は、(理由は薄弱だが)避けてきました。しかし WEBで調べてみると、キーの押し下げを捉えるコードは、APIで、 https://liclog.net/getasynckeystate-function-vba-macro-catia-v5/ などに記事があります。 質問の課題そのものへの回答ではないのですが、 標準モジュールに下記を貼り付けます。 Option Explicit #If Win64 Then Declare PtrSafe Function GetAsyncKeyState Lib "User32.dll" (ByVal vKey As Long) As Integer #Else Declare Function GetAsyncKeyState Lib "User32.dll" (ByVal vKey As Long) As Integer #End If '---------------------------------------------------------------------------------------------' Function ESCPress() As Boolean Const KEY_PRESSED = -32768 ESCPress = (GetAsyncKeyState(vbKeyEscape) And KEY_PRESSED) = KEY_PRESSED End Function '---------------------------------------------------------------------------------------------' Function UPPress() As Boolean Const KEY_PRESSED = -32768 UPPress = (GetAsyncKeyState(vbKeyUp) And KEY_PRESSED) = KEY_PRESSED End Function '---------------------------------------------------------------------------------------------' Function DownPress() As Boolean Const KEY_PRESSED = -32768 DownPress = (GetAsyncKeyState(vbKeyDown) And KEY_PRESSED) = KEY_PRESSED End Function '---------------------------------------------------------------------------------------------' Function RightPress() As Boolean Const KEY_PRESSED = -32768 RightPress = (GetAsyncKeyState(vbKeyRight) And KEY_PRESSED) = KEY_PRESSED End Function '---------------------------------------------------------------------------------------------' Function LeftPress() As Boolean Const KEY_PRESSED = -32768 LeftPress = (GetAsyncKeyState(vbKeyLeft) And KEY_PRESSED) = KEY_PRESSED End Function Function PressCtrl() As Boolean Const KEY_PRESSED = -32768 PressCtrl = (GetAsyncKeyState(vbKeyControl) And KEY_PRESSED) = KEY_PRESSED End Function '---------------------------------------------------------------------------------------------' Sub CATMain() MsgBox "キー入力ループ開始" Do If ESCPress = True Then Exit Do 'Escキーが押された時、ループから抜け出す DoEvents 'これが無いと最悪の場合CATIAがフリーズ If UPPress = True Then '上矢印キーが押された時は以下の処理を行う MsgBox "上矢印キーが押されました" End If If DownPress = True Then '下矢印キーが押された時は以下の処理を行う MsgBox "下矢印キーが押されました" End If If LeftPress = True Then '左矢印キーが押された時は以下の処理を行う MsgBox "左矢印キーが押されました" End If If RightPress = True Then '右矢印キーが押された時は以下の処理を行う MsgBox "右矢印キーが押されました" End If '--- If PressCtrl = True Then '右矢印キーが押された時は以下の処理を行う MsgBox "CTRLキーが押されました" End If Loop MsgBox "キー入力ループから抜け出しました" End Sub ーーー これで、Sub CATMain()部を選択して、実行(状態に)すると、プログラムで、待機状態になり、 CTRLキーを押すと、CTRLを押したと、Msgboxが表示されます。 この後に、したい処理を書くと、良いわけですが、ループ中だし、実行後どれだけの時間の間待てばよいか、保証はないわけです。  だから、多分質問者のしたいことを賄うのは、適してないように思います。 だから他の方法を考えるべきと思いますが。 ーーー Application.OnkeyなどというのもVBAにあるが、CTRL+何かのキーの組み合わせを検知するもののようです。マクロ実行のショートカットキー的使用など。 ーー 上記のコードはWEBから拾ったものをそのまま、2つ組み合わせたので、 (上下左右の)矢印キーとCTRLキーの5つのどれかを検出コードになっています。 余分なら矢印キーの4か所のFunction-EndFunctionコード行を削除してみてください。 他キーの例も参考になると思ってそのままにしました。

ID_20150222
質問者

お礼

教えていただきましたコードの動作を確認しました。 回答にも書かれていましたように余分な部分を削除して、 最小限必要な部分のみにしてCATMainを呼び出すことにより、 したいことが実現できました。 ありがとうございました。

  • kon555
  • ベストアンサー率51% (1848/3569)
回答No.1

 ご希望の「CTRLキーを押すと次の処理を続行する」という機能を実装しようとすると、ループ処理を延々と回してユーザー操作を監視し続ける必要があり、正直なところ現実的ではありません。  マクロの一時停止と再開は、基本的にはStopステートメントでやるのが定石です。 https://lilia-study.com/excel/excel-vba/stop.html  ただこの場合、再開にはVBE画面からの操作が必要ですので「ユーザーが画面の内容を確認したら」というようなユーザー操作想定には向きません。    なので「 CTRLキーを押すと」の部分を諦める事をオススメします。  一時中断前をマクロ1、中断後をマクロ2として分割し、中断画面に再開ボタンを作っておいて、それをクリックしたらマクロ2実行、とすれば無理なく実装できます。

ID_20150222
質問者

お礼

回答ありがとうございます。 教えて頂きましたことは今後の参考にさせていただきます。

関連するQ&A