2025/05/07(Wed) 21:46:56 編集(投稿者)
多分以下の仕組みでタブレットモード?の時は「最大化」はしないようになるはず
仕組みは
1. フォームに「最大化」してと要求があった時
2. デバイスのキーボードを検索
3. キーボードが1件もない場合、タブレットモードとして判定
4. タブレットモードの場合、「最大化」をキャンセルする。
ただ正確には「Surface Go 4」のキーボードデバイスが接続しているか?なんだよね...
メーカーが違うとその機種専用のキーボードで判断してるから
どっかに判定値が入っていてそれで判断してると思う。
環境がないもので推測ばっかりで申し訳ないです。
----- Form3というフォーム(Form3.vb)を作成したとして -----
Imports System.Security.Permissions
Public Class Form3
    <SecurityPermission(SecurityAction.Demand,
    Flags:=SecurityPermissionFlag.UnmanagedCode)>
    Protected Overrides Sub WndProc(ByRef m As Message)
        'Const WM_SETTINGCHANGE As Integer = &H1A
        'Const WM_DEVICECHANGE As Integer = &H219
        'Const DBT_DEVNODES_CHANGED = &H7            'デバイスがシステムに追加されたか、システムから削除されました。
        'Const DBT_QUERYCHANGECONFIG = &H17          '現在の構成を変更するためのアクセス許可が要求されます (ドッキングまたはドッキング解除)。
        'Const DBT_CONFIGCHANGED = &H18              'ドッキングまたはドッキング解除により、現在の構成が変更されました。
        'Const DBT_CONFIGCHANGECANCELED = &H19       '現在の構成を変更する要求 (ドックまたはドッキング解除) が取り消されました。
        'Const DBT_DEVICEARRIVAL = &H8000            'デバイスまたはメディアが挿入され、使用可能になりました。
        'Const DBT_DEVICEQUERYREMOVE = &H8001        'デバイスまたはメディアの一部を削除するためのアクセス許可が要求されます。 どのアプリケーションでも、この要求を拒否し、削除を取り消すことができます。
        'Const DBT_DEVICEQUERYREMOVEFAILED = &H8002  'デバイスまたはメディアの一部を削除する要求が取り消されました。
        'Const DBT_DEVICEREMOVEPENDING = &H8003      'デバイスまたはメディアの一部が削除されようとしています。 拒否できません。
        'Const DBT_DEVICEREMOVECOMPLETE = &H8004     'デバイスまたはメディアが削除されました。
        'Const DBT_DEVICETYPESPECIFIC = &H8005       'デバイス固有のイベントが発生しました。
        'Const DBT_CUSTOMEVENT = &H8006              'カスタム イベントが発生しました。
        'Const DBT_USERDEFINED = &HFFFF              'このメッセージの意味は、ユーザー定義です。
        Const WM_SYSCOMMAND As Integer = &H112
        Const SC_MAXIMIZE = &HF030                  'ウィンドウを最大化します。
        'Debug.Print("WndProc m.Msg = &h{0:X}", m.Msg)
        Select Case m.Msg
            'Case WM_DEVICECHANGE
            '    'デバイスまたはコンピューターのハードウェア構成の変更をアプリケーションに通知します。
            '    'https://learn.microsoft.com/ja-jp/windows/win32/devio/wm-devicechange
            '    Debug.Print("WM_DEVICECHANGE {0} {1}", m.WParam, m.LParam)
            '    'デスクトップPCでキーボードのUSBを抜き差しすると
            '    'm.WParam = DBT_DEVNODES_CHANGED が発生
            '    'GetKeyboardLayout APIでも取得できてるし...
            '    'Surface Go 4 だと
            '    'm.WParam = DBT_QUERYCHANGECONFIG
            '    'm.WParam = DBT_CONFIGCHANGED
            '    'かな?
            '    Select Case m.WParam.ToInt64
            '        Case DBT_DEVNODES_CHANGED
            '    End Select
            'Case WM_SETTINGCHANGE
            '    ' SystemParametersInfo 関数がシステム全体の設定を変更した時
            '    'https://learn.microsoft.com/ja-jp/windows/win32/winmsg/wm-settingchange
            Case WM_SYSCOMMAND
                '最大化ボタン、最小化ボタン、復元ボタン、または閉じるボタンを選択したときに
                'https://learn.microsoft.com/ja-jp/windows/win32/menurc/wm-syscommand
                Select Case (m.WParam.ToInt64() And &HFFF0L)
                    Case SC_MAXIMIZE
                        ' キーボードが未接続の状態
                        If Devices.IsKeyboardConnected() = False Then
                            ' WndProc標準処理をスキップする事で最大化をさせない。
                            m.Result = IntPtr.Zero
                            Return
                        End If
                End Select
        End Select
        ' WndProc標準処理を行う
        MyBase.WndProc(m)
    End Sub
End Class
----- Form3終わり -----
----- Devicesというモジュールファイル(Devices.vb)だとして -----
Imports System.Runtime.InteropServices
Module Devices
    Private Const RIM_TYPEKEYBOARD As Integer = 1
    Private Const RIDI_DEVICENAME As Integer = &H20000007
    <StructLayout(LayoutKind.Sequential)>
    Private Structure RAWINPUTDEVICELIST
        Public hDevice As IntPtr
        <MarshalAs(UnmanagedType.U4)>
        Public dwType As Integer
    End Structure
    <StructLayout(LayoutKind.Sequential)>
    Private Structure RAWINPUTDEVICE
        <MarshalAs(UnmanagedType.U2)>
        Public usUsagePage As System.UInt16
        <MarshalAs(UnmanagedType.U2)>
        Public usUsage As System.UInt16
        <MarshalAs(UnmanagedType.U4)>
        Public dwFlags As Integer
        Public hwndTarget As IntPtr
    End Structure
    <DllImport("User32.dll", SetLastError:=True)>
    Private Function GetRawInputDeviceList(
            ByVal pRawInputDeviceList As IntPtr,
            ByRef uiNumDevices As UInteger,
            ByVal cbSize As UInteger
        ) As UInteger
    End Function
    <DllImport("User32.dll", SetLastError:=True)>
    Private Function GetRawInputDeviceInfo(
             ByVal hDevice As IntPtr,
             ByVal uiCommand As UInteger,
             ByVal pData As IntPtr,
             ByRef pcbSize As UInteger
        ) As UInteger
    End Function
    ''' <summary>
    ''' キーボードが接続しているか判定する。
    ''' </summary>
    ''' <returns>キーボードが接続している場合は true。それ以外の場合は false。</returns>
    Public Function IsKeyboardConnected() As Boolean
        Dim result As Boolean = False
        '----- デバイス一覧を取得する
        Dim NumberOfDevices As Integer = 0
        Dim deviceCount As UInteger = 0
        Dim dwSize As Integer = Marshal.SizeOf(GetType(RAWINPUTDEVICELIST))
        If GetRawInputDeviceList(IntPtr.Zero, deviceCount, CType(dwSize, UInteger)) = 0 Then
            Dim pRawInputDeviceList As IntPtr = Marshal.AllocHGlobal(CType((dwSize * deviceCount), Integer))
            GetRawInputDeviceList(pRawInputDeviceList, deviceCount, CType(dwSize, UInteger))
            For index As Integer = 0 To deviceCount - 1
                Dim pcbSize As UInteger = 0
                Dim rid As RAWINPUTDEVICELIST =
                    CType(
                        Marshal.PtrToStructure(
                            New IntPtr((pRawInputDeviceList.ToInt64 + (dwSize * index))),
                            GetType(RAWINPUTDEVICELIST)),
                        RAWINPUTDEVICELIST)
                GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICENAME, IntPtr.Zero, pcbSize)
                If pcbSize > 0 Then
                    If rid.dwType = RIM_TYPEKEYBOARD Then
                        '----- キーボードデバイスが存在する場合
                        result = True
                        Exit For
                    End If
                End If
            Next
            Marshal.FreeHGlobal(pRawInputDeviceList)
        Else
            '----- API失敗だがキーボードはある事とする。
            result = True
        End If
        Return result
    End Function
End Module
----- Devices終わり -----