windows form でキーを押しながらマウス操作を取得したいです

タグの編集
投稿者 snowmansnow  (社会人) 投稿日時 2021/11/14 20:25:50

 こんばんは、るきお様、魔界の仮面弁士様、皆様
  VB.NETでwindows form でキーを押しながらマウス操作を取得したいです。
  フォームにボタンが無い時は、動きそうでしたが、
  ボタンを配置したら、キーの反応が無くなりました。
Imports System.Drawing
Imports System.Windows.Forms
Public Class Form1

    Public k As String
    Public x As Long
    Public y As Long
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    End Sub

    Private Sub Form1_MouseUp(ByVal sender As ObjectByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        'フォーム上の座標でマウスポインタの位置を取得する 
        '画面座標でマウスポインタの位置を取得する 
        Dim sp As System.Drawing.Point = System.Windows.Forms.Cursor.Position
        '画面座標をクライアント座標に変換する 
        Dim cp As System.Drawing.Point = Me.PointToClient(sp)
        'X座標を取得する 
        Dim x As Integer = cp.X
        'Y座標を取得する 
        Dim y As Integer = cp.Y
        'https://dobon.net/vb/dotnet/system/cursorposition.html 

        If e.Button = MouseButtons.Left Then
            MsgBox(k & "クリックしました!(" & x & "," & y & ")")
            '   Me.CreateGraphics.Clear(Me.BackColor) 
            Me.CreateGraphics.FillEllipse(Brushes.Red, x - 5, y - 5, 10, 10)
            'http://hanatyan.sakura.ne.jp/dotnet/zu05.htm 
        Else
            If e.Button = MouseButtons.Right Then
                MsgBox(k & "右クリックしました!(" & x & "," & y & ")")
                '   Me.CreateGraphics.Clear(Me.BackColor) 
                Me.CreateGraphics.FillEllipse(Brushes.Red, x - 5, y - 5, 10, 10)
                'http://hanatyan.sakura.ne.jp/dotnet/zu05.htm 
            End If
        End If
        'https://dobon.net/vb/bbs/log3-46/27779.html 

    End Sub

    Private Sub Form1_KeyDown(ByVal sender As System.ObjectByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
        k = e.KeyCode
        MsgBox(e.KeyCode)
        'http://rucio.o.oo7.jp/main/dotnet/shokyu/standard21.htm 
    End Sub
    Private Sub Form1_Keyup(ByVal sender As System.ObjectByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyUp
        k = ""
    End Sub

    Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
        Dim g As Graphics = Me.CreateGraphics
        Dim fnt As New Font("IPAmj明朝", 180)
        '文字列を位置(0,0)、青色で表示 
        g.DrawString(ChrW(&HD867) & ChrW(&HDE3D) & ChrW(&HDB40) & ChrW(&HDD03), fnt, Brushes.Blue, 0, 0)
        'リソースを解放する 
        fnt.Dispose()
        g.Dispose()
        'http://pckowaza.web.fc2.com/html/vbdotnet_graphics_drawstringtoform_basic.html 
        'http://bbs.wankuma.com/index.cgi?mode=al2&namber=67412&KLOG=114 
        'http://dobon.net/vb/dotnet/graphics/drawstring.html 
        'http://hanatyan.sakura.ne.jp/dotnet/zu05.htm 

    End Sub

End Class

 上のボタン有は、マウスしか反応しません
 何故なのかわからず、助けて欲しいです。
 よろしくお願いします


投稿者 るきお(管理者)  (社会人) 投稿日時 2021/11/14 21:21:37
フォームの KeyPreviewプロパティを True にすると、うまく反応すると思いますよ。
キー入力を受け取るのは、フォーカスのあるコントロールなので、ボタンにフォーカスがある状態では、通常Formのキー入力系のイベントは動作しません。
KeyPreviewプロパティをTrueにすると、この場合でもフォームがイベントを受け取れるようになります。


ところで、
>こんばんは、るきお様、魔界の仮面弁士様、皆様
いつも投稿ありがとうございます。snowmansnow さんの投稿は単なる質問ではなく、いろいろな技術的な情報が含まれており、とてもうれしく思っています。
名指しでご挨拶いただくのもうれしい気持ちではあるのですが、他の方々が回答しにくくなってしまいますので、初回投稿時点では個人を名指しすることを避けていただけるとありがたいです。
答えを知っていたり、何か提案があったり、質問があったりする人は誰でも書き込んで良いという雰囲気の掲示板にしたいのです。
(ちなみに、私はご指名いただかなくても回答できるものは回答します。魔界の仮面弁士さんは私以上に手広く回答されています。)


>上のボタン有は、マウスしか反応しません
> 何故なのかわからず、助けて欲しいです。
もう少し具体的に書いていただけると助かります。
「反応」の意味が文章からはわからずソースコードを読んで推測する必要がありました。

たとえば、次のように書いていただけると推測の必要がなく、ポイントがすぐにわかります。ポイントがすぐにわかるとその分回答を考えたり、調べてみる時間が増えてお互い得です。
キーボードのキーを押すと、Form1_KeyDownが実行されMsgBoxが表示されることを想定していますが、実際には表示されません。
投稿者 snowmansnow  (社会人) 投稿日時 2021/11/14 21:44:26

  こんばんは、るきお様お返事ありがとうございます。
  >KeyPreviewプロパティをTrueにすると、この場合でもフォームがイベントを受け取れるようになります。
  あっという間に解決頂きありがとうございます!!
 皆さん凄いです。

 >個人を名指しすることを避けて
  ごめんなさい。気を付けます。

 >もう少し具体的に書いていただけると助かります。
  >キーボードのキーを押すと、
  >Form1_KeyDownが実行されMsgBoxが表示されることを想定していますが、
  >実際には表示されません。
 全くその通りで、自己的な文章で申し訳ございません。
 るきお様や、他の皆さんにも分かりやすい文章に気を付けます。

 皆さんに助けられて、色々やってみたい事が増えて楽しいです。
 るきお様のwebが検索エンジンでhitすることも多く、大変勉強になります。
 また宜しくお願い致します。

 
  
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2021/11/16 20:28:26
解決はしているようですが、元コードについて気になった点を。
本題から外れますが、蛇足までに。


マウスイベントのところ:
> Private Sub Form1_MouseUp(…) Handles MyBase.MouseDown
ハンドラ名とイベント名が不一致なので誤解の元になりそうです。

> Me.CreateGraphics.FillEllipse(Brushes.Red, x - 5, y - 5, 10, 10)
Graphics を Dispose し忘れていますよ。
Click イベント の方では Dispose されているのですけれどね。

ちなみに、CreateGraphics で描いた内容は、フォームの最小化やリサイズなどといった要因で容易に消えてしまいますし、描画アイテム数が多い場合には、描画経過が表示されてちらつくことがあります。

永続的な描画が必要な場合には、CreateGraphics 以外の手法が使われることが多いです。

案1) BackgroundImage (PictureBox な Image でも可)に Bitmap を設定しておき、
    その Bitmap に対して描画するようにする。(Bitmap の描画後には Invalidate メソッドを呼ぶ)

案2) 描画すべき座標をすべて覚えておき、Paint イベントで e.Graphics に再描画する

もし、CreateGraphics を使った場合でもちらつきを減らしたい場合には、
BufferedGraphics クラスを併用することで、ダブルバッファリングが可能になります。
https://docs.microsoft.com/ja-jp/dotnet/desktop/winforms/advanced/how-to-manually-render-buffered-graphics?view=netframeworkdesktop-4.8


キーイベントのところ:
> k = e.KeyCode
ではなく、「k = e.KeyCode.ToString("G")」とした方が良いですね。
そうすれば、Option Strict On の時にもエラーになりません。

列挙型の場合、"G" 書式以外には、"F"、"D"、"X" 書式が使えます。
e.KeyCode.ToString() は e.KeyCode.ToString("G") と同義です。


それと、KeyDown 時に MsgBox を表示していますが、このような確認方法をとると、
その後の KeyUp イベントを取りこぼしてしまう可能性が高くなるので、あまりお奨めしません。

マウスやキーボード操作を追跡する場合、メッセージボックスを表示すると、
処理が割り込まれてしまうため、本来のイベント処理が滞ってしまいがちです。
連続したイベント処理に対する一時的な確認が必要な場合には、
 Me.Text = $"MouseUp:{e.Button} , {e.Location}"
のように、タイトルバーや Label などに記載する方が良いでしょう。
履歴をとりたい場合は、ListBox に書き連ねたり、Debug.WriteLine を使うのも便利です。
投稿者 snowmansnow  (社会人) 投稿日時 2021/11/16 23:13:26
こんばんは魔界の仮面弁士様、御返事ありがとうございます。
>マウスイベントのところ:
>> Private Sub Form1_MouseUp(…) Handles MyBase.MouseDown
>ハンドラ名とイベント名が不一致なので誤解の元になりそうです。
気が付きませんでした。
UPでDownなんて、とんちんかんでした。ごめんなさい。

>> Me.CreateGraphics.FillEllipse(Brushes.Red, x - 5, y - 5, 10, 10)
>Graphics を Dispose し忘れていますよ。
宣言して、Disposeする形に変更いたしました。

>案1) 
御教授の形に変更してみました。

>案2) 
配列の形にしてみましたが、Paintのところが良くわかりませんでした。


>> k = e.KeyCode
>ではなく、「k = e.KeyCode.ToString("G")」とした方が良いですね。
直してみたのですが、この形で、2つ以上の複数キー同時押しは、
どのように取得するのでしょうか?

>それと、KeyDown 時に MsgBox を表示していますが、このような確認方法をとると、
>その後の KeyUp イベントを取りこぼしてしまう可能性が高くなるので、あまりお奨めしません。
inkpictureの質問の際にも指摘されておりましたが、癖で
また安直に確認用に残してしまいました。
御教授のコードにしてみました。
Imports System.Drawing
Imports System.Windows.Forms
Imports System.IO
Imports System.Text

Public Class Form1

    Public k As String
    Public x As Long
    Public y As Long
    Public kchar As String
    Public m() As String
    Public xp() As Long
    Public yp() As Long
    Public key() As String
    Public cnt As Long
    Dim col As Color
    'https://social.msdn.microsoft.com/Forums/ja-JP/4086f247-9821-4f94-a610-335428ea4629/brushescolor12392rgb12420argb1239833394124791245212503123982279325563 

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.KeyPreview = True
        'https://docs.microsoft.com/ja-jp/office/vba/api/access.form.keypreview 
        'http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=30670 
    End Sub
    Private Sub Form1_MouseUp(ByVal sender As ObjectByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp

        Me.Text = $"MouseUp:{e.Button} , {e.Location}"

        cnt = cnt + 1
        ReDim Preserve m(cnt), xp(cnt), yp(cnt), key(cnt)

        'フォーム上の座標でマウスポインタの位置を取得する 
        '画面座標でマウスポインタの位置を取得する 
        Dim sp As System.Drawing.Point = System.Windows.Forms.Cursor.Position
        '画面座標をクライアント座標に変換する 
        Dim cp As System.Drawing.Point = Me.PointToClient(sp)
        'X座標を取得する 
        Dim x As Integer = cp.X
        'Y座標を取得する 
        Dim y As Integer = cp.Y
        'https://dobon.net/vb/dotnet/system/cursorposition.html 
        Dim rc, gc, bc As Long

        If e.Button = MouseButtons.Left Then
            'MsgBox(kchar & "クリックしました!(" & x & "," & y & ")") 
            '   Me.CreateGraphics.Clear(Me.BackColor) 
            m(cnt) = "L"
            col = Color.FromArgb(255, 0, 0)
        End If
        If e.Button = MouseButtons.Right Then
            'MsgBox(kchar & "クリックしました!(" & x & "," & y & ")") 
            '   Me.CreateGraphics.Clear(Me.BackColor) 
            m(cnt) = "R"
            col = Color.FromArgb(0, 255, 0)
        End If
        key(cnt) = k
        xp(cnt) = x
        yp(cnt) = y
        'https://dobon.net/vb/bbs/log3-46/27779.html 

        Dim myBrush As New SolidBrush(col)
        myBrush.Color = Color.FromArgb(200, col)
        Dim g As Graphics = Me.CreateGraphics
        g.FillEllipse(myBrush, x - 5, y - 5, 10, 10)
        g.Dispose()
        'http://hanatyan.sakura.ne.jp/dotnet/zu05.htm 

    End Sub

投稿者 snowmansnow  (社会人) 投稿日時 2021/11/16 23:16:39
また長かったので追加です
    Private Sub Form1_KeyDown(ByVal sender As System.ObjectByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
        'kchar = "" 
        k = e.KeyCode.ToString("G")
        'https://developer.mozilla.org/en-US/docs/Web/CSS/color_value 
        'http://rucio.o.oo7.jp/main/dotnet/shokyu/standard21.htm 
    End Sub
    Private Sub Form1_Keyup(ByVal sender As System.ObjectByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyUp
        k = ""
    End Sub

    Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click

        'http://www.nextftp.com/swlabo/m1_vbnet/hp_experiment/exp902.htm 
        Dim img As New Bitmap(Me.Width, Me.Height)
        Dim g As Graphics = Graphics.FromImage(img)

        Dim fnt As New Font("IPAmj明朝", 180)
        '文字列を位置(0,0)、青色で表示 
        g.DrawString(ChrW(&HD867) & ChrW(&HDE3D) & ChrW(&HDB40) & ChrW(&HDD03), fnt, Brushes.Blue, 0, 0)
        'リソースを解放する 
        fnt.Dispose()
        g.Dispose()
        '作成した画像を表示する 
        Dim form As Form
        form = Me
        form.BackgroundImage = img

        '  Dim g As Graphics = Me.CreateGraphics 
        'http://pckowaza.web.fc2.com/html/vbdotnet_graphics_drawstringtoform_basic.html 
        'http://bbs.wankuma.com/index.cgi?mode=al2&namber=67412&KLOG=114 
        'http://dobon.net/vb/dotnet/graphics/drawstring.html 
        'http://hanatyan.sakura.ne.jp/dotnet/zu05.htm 

    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim sjisEnc As Encoding = Encoding.GetEncoding("Shift_JIS")
        Dim writer As System.IO.StreamWriter
        'MsgBox(cnt) 
        writer = My.Computer.FileSystem.OpenTextFileWriter("C:\Users\Y2\Desktop\key2.txt"True, sjisEnc)
        Dim c As Long
        For c = 1 To cnt
            writer.WriteLine(m(c) & "," & xp(c) & "," & yp(c) & "," & key(c))
        Next
        writer.Close()
    End Sub
End Class

まだ、わからない事ばかりで、Paintの所も教えて頂けるとありがたいです。
MymbaseとMeもまだ呑み込めてません・・・
こんがらがってきました・・・

最初にボタン1を押して、キー、マウス操作をして、ボタン2を押します。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2021/11/17 10:20:58
> 配列の形にしてみましたが、Paintのところが良くわかりませんでした。
たとえばこんな感じ。

Partial Public Class Form1
  '描画する箱の一覧 
  Private boxes As New List(Of Rectangle)()
  '現在選択中の箱 
  Private selectedBox As Rectangle?
  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    KeyPreview = True
  End Sub

  Private Sub Form1_MouseClick(sender As Object, e As MouseEventArgs) Handles Me.MouseClick
    '既存の箱があれば、選択状態にするため selectedBox 変数に入れておく 
    selectedBox = boxes.FirstOrDefault(Function(b) b.Contains(e.Location))
    If selectedBox.HasValue AndAlso selectedBox.Value.IsEmpty Then
      selectedBox = Nothing
      'クリックされるたびに 15x15 サイズの箱を追加する 
      boxes.Insert(0, New Rectangle(e.X - 7, e.Y - 7, 15, 15))
    End If
    '描画すべき内容が変化したことを Form に知らせる 
    Invalidate()
  End Sub
  Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
    For Each box In boxes
      '選択している箱は赤、未選択は黒で描画する 
      e.Graphics.DrawRectangle(If(box = selectedBox, Pens.Red, Pens.Black), box)
    Next
  End Sub

  Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
    If selectedBox.HasValue Then
      '箱の選択中に DELETE が押されればその箱を削除、ESCAPE なら選択解除 
      If e.KeyCode = Keys.Delete Then
        boxes.Remove(selectedBox.Value)
        Invalidate()
      ElseIf e.KeyCode = Keys.Escape Then
        selectedBox = Nothing
        Invalidate()
      End If
    End If
  End Sub
End Class




> 直してみたのですが、この形で、2つ以上の複数キー同時押しは、
> どのように取得するのでしょうか?
どのキーとどのキーの同時押しを想定しておられますか?

まず KeyDown/KeyPress/KeyUp は、修飾キー以外の同時押しを
捉えられるような設計にはなっていません。

Shift, Ctrl, Alt といった「修飾キー」は同時押しに対応していますが、
それ以外のキーは、そもそも同時押しを保証していないためです。
ゲーミングキーボードの中には、同時入力への反応が良いものもあるようですが、
通常のキーボードの場合、下記のような制限があるため、必ずしも同時入力に対応できません。
http://dailynewsagency.com/2014/03/08/microsoft-applied-sciences-group-bbw/


そうした制限があることを踏まえた上で、複数同時押しの判定のために
「指定したキーが現在押された状態になっているかどうか」を調べることは可能です。
参照設定に PresentationCore と WindowsBase を加えた上で、下記のようにします。

' 現在、[←]キーが押された状態になっていれば True 
If System.Windows.Input.Keyboard.GetKeyStates(System.Windows.Input.Key.Left).HasFlag(System.Windows.Input.KeyStates.Down) Then


あるいは、RawInput でキューを捕らえるといった手法もあります。


> MymbaseとMeもまだ呑み込めてません・・・
MyBase / MyClass / Me のことでしょうか?

https://shimonss.hatenablog.com/entry/2017/06/04/143411
https://smdn.jp/programming/vb.net/me_myclass_mybase/
http://rucio.a.la9.jp/main/VBdotNet/Advance/Advance3.htm
https://docs.microsoft.com/ja-jp/dotnet/visual-basic/programming-guide/program-structure/me-my-mybase-and-myclass


Me は自身のインスタンスを表し、
MyClass は、自クラスのメンバーを参照する際に利用し、
MyBase は、基底クラスのメンバーを参照する際に利用します。

この違いがあるため、イベントハンドラーの
 Handles MyBase.Load
 Handles Me.Load
は、厳密に言えば異なる結果になることがあります。

Partial Public Class Form1
  '通常であれば、これら 3 つは同じように動作しますが… 
  Private Sub Form1_Load_0(sender As Object, e As EventArgs) Handles Me.Load
    ListBox1.Items.Add("Me.Load")
  End Sub
  Private Sub Form1_Load_1(sender As Object, e As EventArgs) Handles MyBase.Load
    ListBox1.Items.Add("MyBase.Load")
  End Sub
  Private Sub Form1_Load_2(sender As Object, e As EventArgs) Handles MyClass.Load
    ListBox1.Items.Add("MyClass.Load")
  End Sub

  '独自の Load イベントがシャドーイングされていた場合、上記の違いが見えてきます 
  Public Shadows Event Load As EventHandler
  Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    '自クラスである Form1 で定義された Load イベントを呼び出す 
    RaiseEvent Load(Me, EventArgs.Empty)
    'この場合、基底クラス(Form) の Load では無いので、MyBase.Load は発生しない 
  End Sub
  ' 上記の「Shadows Event Load」と「Sub Button1_Click」が無買った場合は、 
  ' "Me.Load", "MyBase.Load", "MyClass.Load" が同じように動作します 

  Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    '基底クラスである Form の Load イベントを呼び出すための Protected なメソッド 
    MyBase.OnLoad(EventArgs.Empty)
  End Sub
End Class
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2021/11/17 11:17:52
> Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
>  Dim img As New Bitmap(Me.Width, Me.Height)
(中略)
>  '作成した画像を表示する 
>  Dim form As Form
>  form = Me
>  form.BackgroundImage = img

このコードですと、クリックが複数回行われた場合、
前回クリックした時に割り当ててあった BackgroundImage に対して
明示的な Dispose が行われていないことになってしまいます。


クリックするたびに、新しい Bitmap に差し換えるのであれば、
不要になった以前の古い Bitmap を Dispose することが望ましいです。
放っておいても GC はされますが…明示的に処分できる状況ならば、
きちんと片づけた方が良いですね。

あるいは、毎回 Bitmap を作り直すのではなく、
現在表示中の Bitmap に対して重ね描きするのであれば、
Graphics.FromImage(BackgroundImage) に対して描いて Invalidate します。
投稿者 snowmansnow  (社会人) 投稿日時 2021/11/17 21:06:44
こんばんは、魔界の仮面弁士様

 こんがらがっていますが、少し解決いたしました。

 >たとえばこんな感じ。
 凄いです。
 いたる所に自分では使えない表現があって、真似をしたり、
 るきお様のwebなどで勉強しなくては分からない事ばかりでした。

 >どのキーとどのキーの同時押しを想定しておられますか?
 アルファベットと数字の同時複数押しを考えてました。
 マウスクリックのポイントの意味を表現しようとしていました。

 >Shift, Ctrl, Alt といった「修飾キー」は同時押しに対応していますが、
>それ以外のキーは、そもそも同時押しを保証していないためです。
 他のwebでも、最新のキーが取得されるような記述でした。

 それを逆手にとって
    kochakoさんのweb(下記)を参考にLISTに代入していきます
   'https://seesaawiki.jp/pg-note/d/%ca%a3%bf%f4%a5%ad%a1%bc%b2%a1%b2%bc%be%f5%c2%d6%a4%ce%c8%bd%c4%ea
   リストに追加、削除する形にしましたので、
  一応、どんなキーでも何個でも押した事がわかる仕様になりました

 >MyBase / MyClass / Me のことでしょうか?
 はい、オブジェクト指向?のプログラミングをしていないので、
 >  '通常であれば、これら 3 つは同じように動作しますが… 
 で、同じに感じるレベルです。
 これもるきお様のwebなどで勉強しなくてはならないです。

>このコードですと、クリックが複数回行われた場合、
>前回クリックした時に割り当ててあった BackgroundImage に対して
>明示的な Dispose が行われていないことになってしまいます。
>きちんと片づけた方が良いですね。 
 これも、解決できず、1回だけ有効な形に変更してみました。


Imports System.Drawing
Imports System.Windows.Forms
Imports System.IO
Imports System.Text

Public Class Form1

    Public x, y, ini, cnt As Long
    Public k, kchar As String
    Public m(), keysA() As String
    Public xp(), yp() As Long
    Public keys = New List(Of String)()

    Dim col As Color

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.KeyPreview = True
        'https://docs.microsoft.com/ja-jp/office/vba/api/access.form.keypreview 
        'http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=30670 
        ini = 0
    End Sub

    Private Sub Form1_MouseUp(ByVal sender As ObjectByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp

        Me.Text = $"MouseUp:{e.Button} , {e.Location}"

        cnt = cnt + 1
        ReDim Preserve m(cnt), xp(cnt), yp(cnt), keysA(cnt)

        'フォーム上の座標でマウスポインタの位置を取得する 
        '画面座標でマウスポインタの位置を取得する 
        Dim sp As System.Drawing.Point = System.Windows.Forms.Cursor.Position
        '画面座標をクライアント座標に変換する 
        Dim cp As System.Drawing.Point = Me.PointToClient(sp)
        'X座標を取得する 
        Dim x As Integer = cp.X
        'Y座標を取得する 
        Dim y As Integer = cp.Y
        'https://dobon.net/vb/dotnet/system/cursorposition.html 
        Dim rc, gc, bc As Long

        If e.Button = MouseButtons.Left Then
            'MsgBox(kchar & "クリックしました!(" & x & "," & y & ")") 
            '   Me.CreateGraphics.Clear(Me.BackColor) 
            m(cnt) = "L"
            col = Color.FromArgb(255, 0, 0)
        End If
        If e.Button = MouseButtons.Right Then
            'MsgBox(kchar & "クリックしました!(" & x & "," & y & ")") 
            '   Me.CreateGraphics.Clear(Me.BackColor) 
            m(cnt) = "R"
            col = Color.FromArgb(0, 255, 0)
        End If
        xp(cnt) = x
        yp(cnt) = y
        'https://dobon.net/vb/bbs/log3-46/27779.html 
        keysA(cnt) = TakeOut(keys)
        keys.Clear()
        Invalidate()
    End Sub

投稿者 snowmansnow  (社会人) 投稿日時 2021/11/17 21:08:55

 また長いので、追加です
    Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        For i = 1 To cnt
            Dim myBrush As New SolidBrush(col)
            myBrush.Color = Color.FromArgb(200, col)
            Dim g As Graphics = Me.CreateGraphics
            g.FillEllipse(myBrush, xp(i) - 5, yp(i) - 5, 10, 10)
            g.Dispose()
        Next
        'http://hanatyan.sakura.ne.jp/dotnet/zu05.htm 

    End Sub

    Private Sub Form1_KeyDown(ByVal sender As System.ObjectByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
        'kchar = "" 
        k = e.KeyCode.ToString("G")
        If keys.Contains(k) Then
        Else
            keys.Add(k)
        End If
        'kochakoさんのweb(下記)を参考にLISTに代入していきます 
        'https://seesaawiki.jp/pg-note/d/%ca%a3%bf%f4%a5%ad%a1%bc%b2%a1%b2%bc%be%f5%c2%d6%a4%ce%c8%bd%c4%ea 

        'https://developer.mozilla.org/en-US/docs/Web/CSS/color_value 
        'http://rucio.o.oo7.jp/main/dotnet/shokyu/standard21.htm 
    End Sub
    Private Sub Form1_Keyup(ByVal sender As System.ObjectByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyUp
        k = e.KeyCode.ToString("G")
        keys.Remove(k)
    End Sub

    Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
        ini = ini + 1
        If ini <= 1 Then
            'http://www.nextftp.com/swlabo/m1_vbnet/hp_experiment/exp902.htm 

            Dim img As New Bitmap(Me.Width, Me.Height)
            Dim g As Graphics = Graphics.FromImage(img)

            Dim fnt As New Font("IPAmj明朝", 180)
            '文字列を位置(0,0)、青色で表示 
            g.DrawString(ChrW(&HD867) & ChrW(&HDE3D) & ChrW(&HDB40) & ChrW(&HDD03), fnt, Brushes.Blue, 0, 0)
            'リソースを解放する 
            fnt.Dispose()
            g.Dispose()
            '作成した画像を表示する 
            Dim form As Form
            form = Me
            form.BackgroundImage = img
        Else
        End If
        '  Dim g As Graphics = Me.CreateGraphics 
        'http://pckowaza.web.fc2.com/html/vbdotnet_graphics_drawstringtoform_basic.html 
        'http://bbs.wankuma.com/index.cgi?mode=al2&namber=67412&KLOG=114 
        'http://dobon.net/vb/dotnet/graphics/drawstring.html 
        'http://hanatyan.sakura.ne.jp/dotnet/zu05.htm 

    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim sjisEnc As Encoding = Encoding.GetEncoding("Shift_JIS")
        Dim writer As System.IO.StreamWriter
        MsgBox(cnt)
        writer = My.Computer.FileSystem.OpenTextFileWriter("C:\Users\Y2\Desktop\key2.txt"True, sjisEnc)
        Dim c As Long

        For c = 1 To cnt
            writer.WriteLine(m(c) & "," & xp(c) & "," & yp(c) & "," & keysA(c))
        Next
        writer.Close()
    End Sub
    Function TakeOut(ByVal list As List(Of String)) As String
        Dim keyt As String
        keyt = ""
        For Each e As String In list
            keyt = keyt + e
        Next
        Return keyt
    End Function
End Class

paintも改造してみました。