github.com/rajveermalviya/gamen@v0.1.2-0.20220930195403-9be15877c1aa/internal/win32/keycodes.go (about)

     1  //go:build windows
     2  
     3  package win32
     4  
     5  import (
     6  	"sync/atomic"
     7  	"unicode/utf16"
     8  	"unsafe"
     9  
    10  	"github.com/rajveermalviya/gamen/events"
    11  	"github.com/rajveermalviya/gamen/internal/win32/procs"
    12  )
    13  
    14  func mapVK(vk uintptr, scancode uintptr, extended bool) events.VirtualKey {
    15  	switch vk {
    16  	case procs.VK_CANCEL:
    17  		return events.VirtualKeyCancel
    18  	case procs.VK_HELP:
    19  		return events.VirtualKeyHelp
    20  	case procs.VK_BACK:
    21  		return events.VirtualKeyBackSpace
    22  	case procs.VK_TAB:
    23  		return events.VirtualKeyTab
    24  	case procs.VK_CLEAR:
    25  		return events.VirtualKeyClear
    26  	case procs.VK_RETURN:
    27  		return events.VirtualKeyReturn
    28  	case procs.VK_PAUSE:
    29  		return events.VirtualKeyPause
    30  	case procs.VK_CAPITAL:
    31  		return events.VirtualKeyCapsLock
    32  	case procs.VK_KANA:
    33  		return events.VirtualKeyKana
    34  	case procs.VK_JUNJA:
    35  		return events.VirtualKeyJunja
    36  	case procs.VK_FINAL:
    37  		return events.VirtualKeyFinal
    38  	case procs.VK_KANJI:
    39  		return events.VirtualKeyKanji
    40  	case procs.VK_ESCAPE:
    41  		return events.VirtualKeyEscape
    42  	case procs.VK_CONVERT:
    43  		return events.VirtualKeyConvert
    44  	case procs.VK_NONCONVERT:
    45  		return events.VirtualKeyNonconvert
    46  	case procs.VK_ACCEPT:
    47  		return events.VirtualKeyAccept
    48  	case procs.VK_MODECHANGE:
    49  		return events.VirtualKeyModechange
    50  	case procs.VK_SPACE:
    51  		return events.VirtualKeySpace
    52  	case procs.VK_PRIOR:
    53  		return events.VirtualKeyPageUp
    54  	case procs.VK_NEXT:
    55  		return events.VirtualKeyPageDown
    56  	case procs.VK_END:
    57  		return events.VirtualKeyEnd
    58  	case procs.VK_HOME:
    59  		return events.VirtualKeyHome
    60  	case procs.VK_LEFT:
    61  		return events.VirtualKeyLeft
    62  	case procs.VK_UP:
    63  		return events.VirtualKeyUp
    64  	case procs.VK_RIGHT:
    65  		return events.VirtualKeyRight
    66  	case procs.VK_DOWN:
    67  		return events.VirtualKeyDown
    68  	case procs.VK_SELECT:
    69  		return events.VirtualKeySelect
    70  	case procs.VK_PRINT:
    71  		return events.VirtualKeyPrint
    72  	case procs.VK_EXECUTE:
    73  		return events.VirtualKeyExecute
    74  	case procs.VK_INSERT:
    75  		return events.VirtualKeyInsert
    76  	case procs.VK_DELETE:
    77  		return events.VirtualKeyDelete
    78  	case procs.VK_0:
    79  		return events.VirtualKey0
    80  	case procs.VK_1:
    81  		return events.VirtualKey1
    82  	case procs.VK_2:
    83  		return events.VirtualKey2
    84  	case procs.VK_3:
    85  		return events.VirtualKey3
    86  	case procs.VK_4:
    87  		return events.VirtualKey4
    88  	case procs.VK_5:
    89  		return events.VirtualKey5
    90  	case procs.VK_6:
    91  		return events.VirtualKey6
    92  	case procs.VK_7:
    93  		return events.VirtualKey7
    94  	case procs.VK_8:
    95  		return events.VirtualKey8
    96  	case procs.VK_9:
    97  		return events.VirtualKey9
    98  	case procs.VK_A:
    99  		return events.VirtualKeyA
   100  	case procs.VK_B:
   101  		return events.VirtualKeyB
   102  	case procs.VK_C:
   103  		return events.VirtualKeyC
   104  	case procs.VK_D:
   105  		return events.VirtualKeyD
   106  	case procs.VK_E:
   107  		return events.VirtualKeyE
   108  	case procs.VK_F:
   109  		return events.VirtualKeyF
   110  	case procs.VK_G:
   111  		return events.VirtualKeyG
   112  	case procs.VK_H:
   113  		return events.VirtualKeyH
   114  	case procs.VK_I:
   115  		return events.VirtualKeyI
   116  	case procs.VK_J:
   117  		return events.VirtualKeyJ
   118  	case procs.VK_K:
   119  		return events.VirtualKeyK
   120  	case procs.VK_L:
   121  		return events.VirtualKeyL
   122  	case procs.VK_M:
   123  		return events.VirtualKeyM
   124  	case procs.VK_N:
   125  		return events.VirtualKeyN
   126  	case procs.VK_O:
   127  		return events.VirtualKeyO
   128  	case procs.VK_P:
   129  		return events.VirtualKeyP
   130  	case procs.VK_Q:
   131  		return events.VirtualKeyQ
   132  	case procs.VK_R:
   133  		return events.VirtualKeyR
   134  	case procs.VK_S:
   135  		return events.VirtualKeyS
   136  	case procs.VK_T:
   137  		return events.VirtualKeyT
   138  	case procs.VK_U:
   139  		return events.VirtualKeyU
   140  	case procs.VK_V:
   141  		return events.VirtualKeyV
   142  	case procs.VK_W:
   143  		return events.VirtualKeyW
   144  	case procs.VK_X:
   145  		return events.VirtualKeyX
   146  	case procs.VK_Y:
   147  		return events.VirtualKeyY
   148  	case procs.VK_Z:
   149  		return events.VirtualKeyZ
   150  	case procs.VK_LWIN:
   151  		return events.VirtualKeyLWin
   152  	case procs.VK_RWIN:
   153  		return events.VirtualKeyRWin
   154  	case procs.VK_APPS:
   155  		return events.VirtualKeyContextMenu
   156  	case procs.VK_SLEEP:
   157  		return events.VirtualKeySleep
   158  	case procs.VK_NUMPAD0:
   159  		return events.VirtualKeyNumpad0
   160  	case procs.VK_NUMPAD1:
   161  		return events.VirtualKeyNumpad1
   162  	case procs.VK_NUMPAD2:
   163  		return events.VirtualKeyNumpad2
   164  	case procs.VK_NUMPAD3:
   165  		return events.VirtualKeyNumpad3
   166  	case procs.VK_NUMPAD4:
   167  		return events.VirtualKeyNumpad4
   168  	case procs.VK_NUMPAD5:
   169  		return events.VirtualKeyNumpad5
   170  	case procs.VK_NUMPAD6:
   171  		return events.VirtualKeyNumpad6
   172  	case procs.VK_NUMPAD7:
   173  		return events.VirtualKeyNumpad7
   174  	case procs.VK_NUMPAD8:
   175  		return events.VirtualKeyNumpad8
   176  	case procs.VK_NUMPAD9:
   177  		return events.VirtualKeyNumpad9
   178  	case procs.VK_MULTIPLY:
   179  		return events.VirtualKeyMultiply
   180  	case procs.VK_ADD:
   181  		return events.VirtualKeyAdd
   182  	case procs.VK_SUBTRACT:
   183  		return events.VirtualKeySubtract
   184  	case procs.VK_DECIMAL:
   185  		return events.VirtualKeyDecimal
   186  	case procs.VK_DIVIDE:
   187  		return events.VirtualKeyDivide
   188  	case procs.VK_F1:
   189  		return events.VirtualKeyF1
   190  	case procs.VK_F2:
   191  		return events.VirtualKeyF2
   192  	case procs.VK_F3:
   193  		return events.VirtualKeyF3
   194  	case procs.VK_F4:
   195  		return events.VirtualKeyF4
   196  	case procs.VK_F5:
   197  		return events.VirtualKeyF5
   198  	case procs.VK_F6:
   199  		return events.VirtualKeyF6
   200  	case procs.VK_F7:
   201  		return events.VirtualKeyF7
   202  	case procs.VK_F8:
   203  		return events.VirtualKeyF8
   204  	case procs.VK_F9:
   205  		return events.VirtualKeyF9
   206  	case procs.VK_F10:
   207  		return events.VirtualKeyF10
   208  	case procs.VK_F11:
   209  		return events.VirtualKeyF11
   210  	case procs.VK_F12:
   211  		return events.VirtualKeyF12
   212  	case procs.VK_F13:
   213  		return events.VirtualKeyF13
   214  	case procs.VK_F14:
   215  		return events.VirtualKeyF14
   216  	case procs.VK_F15:
   217  		return events.VirtualKeyF15
   218  	case procs.VK_F16:
   219  		return events.VirtualKeyF16
   220  	case procs.VK_F17:
   221  		return events.VirtualKeyF17
   222  	case procs.VK_F18:
   223  		return events.VirtualKeyF18
   224  	case procs.VK_F19:
   225  		return events.VirtualKeyF19
   226  	case procs.VK_F20:
   227  		return events.VirtualKeyF20
   228  	case procs.VK_F21:
   229  		return events.VirtualKeyF21
   230  	case procs.VK_F22:
   231  		return events.VirtualKeyF22
   232  	case procs.VK_F23:
   233  		return events.VirtualKeyF23
   234  	case procs.VK_F24:
   235  		return events.VirtualKeyF24
   236  	case procs.VK_NUMLOCK:
   237  		return events.VirtualKeyNumLock
   238  	case procs.VK_SCROLL:
   239  		return events.VirtualKeyScrollLock
   240  	case procs.VK_VOLUME_MUTE:
   241  		return events.VirtualKeyVolumeMute
   242  	case procs.VK_VOLUME_DOWN:
   243  		return events.VirtualKeyVolumeDown
   244  	case procs.VK_VOLUME_UP:
   245  		return events.VirtualKeyVolumeUp
   246  
   247  	case procs.VK_SHIFT:
   248  		switch procs.MapVirtualKeyW(scancode, procs.MAPVK_VSC_TO_VK_EX) {
   249  		case procs.VK_LSHIFT:
   250  			return events.VirtualKeyLShift
   251  		case procs.VK_RSHIFT:
   252  			return events.VirtualKeyRShift
   253  		}
   254  
   255  	case procs.VK_CONTROL:
   256  		if extended {
   257  			return events.VirtualKeyRControl
   258  		} else {
   259  			return events.VirtualKeyLControl
   260  		}
   261  
   262  	case procs.VK_MENU:
   263  		if extended {
   264  			if layoutUsesAltgr() {
   265  				return events.VirtualKeyAltgr
   266  			} else {
   267  				return events.VirtualKeyRAlt
   268  			}
   269  		} else {
   270  			return events.VirtualKeyLAlt
   271  		}
   272  
   273  	default:
   274  		switch rune(procs.MapVirtualKeyW(vk, procs.MAPVK_VK_TO_CHAR) & 0x7FFF) {
   275  		case '-':
   276  			return events.VirtualKeyHyphenMinus
   277  		case ';':
   278  			return events.VirtualKeySemicolon
   279  		case '=':
   280  			return events.VirtualKeyEquals
   281  		case ',':
   282  			return events.VirtualKeyComma
   283  		case '.':
   284  			return events.VirtualKeyPeriod
   285  		case '/':
   286  			return events.VirtualKeySlash
   287  		case '`':
   288  			return events.VirtualKeyBackQuote
   289  		case '[':
   290  			return events.VirtualKeyOpenBracket
   291  		case ']':
   292  			return events.VirtualKeyCloseBracket
   293  		case '\\':
   294  			return events.VirtualKeyBackSlash
   295  		case '\'':
   296  			return events.VirtualKeyQuote
   297  		}
   298  	}
   299  
   300  	return events.VirtualKey(vk)
   301  }
   302  
   303  func getChar(keyboardState *[256]byte, vKey uintptr, hkl uintptr) rune {
   304  	var unicodeBytes [5]uint16
   305  	l := procs.ToUnicodeEx(
   306  		vKey,
   307  		0,
   308  		uintptr(unsafe.Pointer(&keyboardState)),
   309  		uintptr(unsafe.Pointer(&unicodeBytes)),
   310  		uintptr(len(unicodeBytes)),
   311  		0,
   312  		hkl,
   313  	)
   314  	if l >= 1 {
   315  		r := utf16.Decode(unicodeBytes[:l])
   316  		if len(r) > 0 {
   317  			return r[0]
   318  		}
   319  	}
   320  	return -1
   321  }
   322  
   323  var currentLayout uintptr
   324  var usesAltGr uint32
   325  
   326  func layoutUsesAltgr() bool {
   327  	hkl := procs.GetKeyboardLayout(0)
   328  	oldHkl := atomic.SwapUintptr(&currentLayout, hkl)
   329  
   330  	if hkl == oldHkl {
   331  		return atomic.LoadUint32(&usesAltGr) != 0
   332  	}
   333  
   334  	var keyboardStateAltgr [256]byte
   335  	var keyboardStateEmpty [256]byte
   336  
   337  	keyboardStateAltgr[procs.VK_MENU] = 0x80
   338  	keyboardStateAltgr[procs.VK_CONTROL] = 0x80
   339  
   340  	for vKey := uintptr(0); vKey < 255; vKey++ {
   341  		keyNoAltgr := getChar(&keyboardStateEmpty, vKey, hkl)
   342  		keyAltgr := getChar(&keyboardStateAltgr, vKey, hkl)
   343  		if keyAltgr != -1 && keyNoAltgr != -1 {
   344  			if keyAltgr != keyNoAltgr {
   345  				atomic.StoreUint32(&usesAltGr, 1)
   346  				return true
   347  			}
   348  		}
   349  	}
   350  
   351  	atomic.StoreUint32(&usesAltGr, 0)
   352  	return false
   353  }