├── croskbsettings-wilco.bin ├── VivaldiKeyboardTester.vcxproj.filters ├── VivaldiKeyboardTester.sln ├── croskbsettings.bin ├── keyboard.h ├── .gitignore ├── VivaldiKeyboardTester.vcxproj └── VivaldiKeyboardTester.cpp /croskbsettings-wilco.bin: -------------------------------------------------------------------------------- 1 | BKrC UWV[VV[V [ X: -------------------------------------------------------------------------------- /VivaldiKeyboardTester.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | Header Files 25 | 26 | 27 | -------------------------------------------------------------------------------- /VivaldiKeyboardTester.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VivaldiKeyboardTester", "VivaldiKeyboardTester.vcxproj", "{4E84D0D9-E1E5-417E-9977-654AD3CD8871}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {4E84D0D9-E1E5-417E-9977-654AD3CD8871}.Debug|x64.ActiveCfg = Debug|x64 17 | {4E84D0D9-E1E5-417E-9977-654AD3CD8871}.Debug|x64.Build.0 = Debug|x64 18 | {4E84D0D9-E1E5-417E-9977-654AD3CD8871}.Debug|x86.ActiveCfg = Debug|Win32 19 | {4E84D0D9-E1E5-417E-9977-654AD3CD8871}.Debug|x86.Build.0 = Debug|Win32 20 | {4E84D0D9-E1E5-417E-9977-654AD3CD8871}.Release|x64.ActiveCfg = Release|x64 21 | {4E84D0D9-E1E5-417E-9977-654AD3CD8871}.Release|x64.Build.0 = Release|x64 22 | {4E84D0D9-E1E5-417E-9977-654AD3CD8871}.Release|x86.ActiveCfg = Release|Win32 23 | {4E84D0D9-E1E5-417E-9977-654AD3CD8871}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {0632B235-577F-4C75-89FA-AF019544B530} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /croskbsettings.bin: -------------------------------------------------------------------------------- 1 | BKrC(jig .0SSW*[*[[[**[KGMOHIPQ]&[]& -------------------------------------------------------------------------------- /keyboard.h: -------------------------------------------------------------------------------- 1 | // 2 | // NtReadFile Output Buffer record structures for this device. 3 | // 4 | 5 | typedef struct _KEYBOARD_INPUT_DATA { 6 | // 7 | // Unit number. E.g., for \Device\KeyboardPort0 the unit is '0', 8 | // for \Device\KeyboardPort1 the unit is '1', and so on. 9 | // 10 | USHORT UnitId; 11 | // 12 | // The "make" scan code (key depression). 13 | // 14 | USHORT MakeCode; 15 | // 16 | // The flags field indicates a "break" (key release) and other 17 | // miscellaneous scan code information defined below. 18 | // 19 | USHORT Flags; 20 | USHORT Reserved; 21 | // 22 | // Device-specific additional information for the event. 23 | // 24 | ULONG ExtraInformation; 25 | 26 | } KEYBOARD_INPUT_DATA, * PKEYBOARD_INPUT_DATA; 27 | 28 | // 29 | // Define the keyboard input data Flags. 30 | // 31 | 32 | #define KEY_MAKE 0 33 | #define KEY_BREAK 1 34 | #define KEY_E0 2 35 | #define KEY_E1 4 36 | #define KEY_TERMSRV_SET_LED 8 37 | #define KEY_TERMSRV_SHADOW 0x10 38 | #define KEY_TERMSRV_VKPACKET 0x20 39 | #define KEY_RIM_VKEY 0x40 40 | #define KEY_FROM_KEYBOARD_OVERRIDER 0x80 41 | #define KEY_UNICODE_SEQUENCE_ITEM 0x100 42 | #define KEY_UNICODE_SEQUENCE_END 0x200 43 | 44 | #define KEY_TYPES (KEY_E0 | KEY_E1 | KEY_RIM_VKEY | KEY_FROM_KEYBOARD_OVERRIDER) 45 | 46 | #define K_LCTRL 0x1D 47 | #define K_LALT 0x38 48 | #define K_LSHFT 0x2A 49 | #define K_ASSISTANT 0x58 50 | #define K_LWIN 0x5B 51 | 52 | #define K_RCTRL 0x1D 53 | #define K_RALT 0x38 54 | #define K_RSHFT 0x36 55 | 56 | #define K_BACKSP 0xE 57 | #define K_DELETE 0x53 58 | #define K_LOCK 0x5D 59 | 60 | #define K_UP 0x48 61 | #define K_DOWN 0x50 62 | #define K_LEFT 0x4B 63 | #define K_RIGHT 0x4D 64 | 65 | #define K_PGUP 0x49 66 | #define K_HOME 0x47 67 | #define K_END 0x4F 68 | #define K_PGDN 0x51 69 | 70 | //ALL VIVALDI USES KEY_E0 71 | 72 | //values from https://github.com/coreboot/chrome-ec/blob/1b359bdd91da15ea25aaffd0d940ff63b9d72bc5/include/keyboard_8042_sharedlib.h#L116 73 | #define VIVALDI_BACK 0x6A 74 | #define VIVALDI_FWD 0x69 75 | #define VIVALDI_REFRESH 0x67 76 | #define VIVALDI_FULLSCREEN 0x11 77 | #define VIVALDI_OVERVIEW 0x12 78 | #define VIVALDI_SNAPSHOT 0x13 79 | #define VIVALDI_BRIGHTNESSDN 0x14 80 | #define VIVALDI_BRIGHTNESSUP 0x15 81 | #define VIVALDI_PRIVACY_TOGGLE 0x16 82 | #define VIVALDI_KBD_BKLIGHT_DOWN 0x17 83 | #define VIVALDI_KBD_BKLIGHT_UP 0x18 84 | #define VIVALDI_KBD_BKLIGHT_TOGGLE 0x1e 85 | #define VIVALDI_PLAYPAUSE 0x1A 86 | #define VIVALDI_MUTE 0x20 87 | #define VIVALDI_VOLDN 0x2e 88 | #define VIVALDI_VOLUP 0x30 89 | #define VIVALDI_NEXT_TRACK 0x19 90 | #define VIVALDI_PREV_TRACK 0x10 91 | #define VIVALDI_MICMUTE 0x1b 92 | 93 | //Wilco uses slightly different keys. Just here for reference as it has a dedicated Fn key 94 | #define WILCO_FULLSCREEN 0x55 95 | #define WILCO_OVERVIEW 0x56 96 | #define WILCO_BRIGHTNESSDN 0x15 97 | #define WILCO_BRIGHTNESSUP 0x11 98 | #define WILCO_PROJECT 0xb 99 | 100 | #define CROSKBHID_BRIGHTNESS_UP 0x01 101 | #define CROSKBHID_BRIGHTNESS_DN 0x02 102 | #define CROSKBHID_KBLT_UP 0x04 103 | #define CROSKBHID_KBLT_DN 0x08 104 | #define CROSKBHID_KBLT_TOGGLE 0x10 105 | 106 | #define REMAP_CFG_MAGIC 'CrKB' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_h.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *_wpftmp.csproj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush personal settings 296 | .cr/personal 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | 333 | # Local History for Visual Studio 334 | .localhistory/ 335 | -------------------------------------------------------------------------------- /VivaldiKeyboardTester.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {4e84d0d9-e1e5-417e-9977-654ad3cd8871} 25 | VivaldiKeyboardTester 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Console 94 | true 95 | 96 | 97 | 98 | 99 | Level3 100 | true 101 | true 102 | true 103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | true 105 | 106 | 107 | Console 108 | true 109 | true 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 118 | true 119 | 120 | 121 | Console 122 | true 123 | 124 | 125 | 126 | 127 | Level3 128 | true 129 | true 130 | true 131 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 132 | true 133 | 134 | 135 | Console 136 | true 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /VivaldiKeyboardTester.cpp: -------------------------------------------------------------------------------- 1 | // VivaldiKeyboardTester.cpp : This file contains the 'main' function. Program execution begins and ends there. 2 | // 3 | 4 | #include 5 | 6 | #define UINT8 uint8_t 7 | #define UINT16 uint16_t 8 | #define UINT32 uint32_t 9 | #define INT32 int32_t 10 | #define USHORT uint16_t 11 | #define ULONG uint32_t 12 | #define PULONG ULONG * 13 | 14 | #include 15 | #define BOOLEAN bool 16 | #define TRUE true 17 | #define FALSE false 18 | 19 | #undef bool 20 | #undef true 21 | #undef false 22 | 23 | #include 24 | 25 | #define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) 26 | #define RtlCopyMemory memcpy 27 | 28 | #undef memcpy 29 | #undef memset 30 | 31 | #include 32 | #include 33 | #include "keyboard.h" 34 | 35 | const UINT8 fnKeys_set1[] = { 36 | 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 37 | 38 | //F13 - F16 39 | 0x64, 0x64, 0x66, 0x67 40 | }; 41 | 42 | void ReceiveKeys_Guarded(PKEYBOARD_INPUT_DATA startPtr, PKEYBOARD_INPUT_DATA endPtr, PULONG InputDataConsumed); 43 | 44 | #define INTFLAG_NEW 0x1 45 | #define INTFLAG_REMOVED 0x2 46 | 47 | #include 48 | 49 | typedef struct RemapCfgKey { 50 | USHORT MakeCode; 51 | USHORT Flags; 52 | } RemapCfgKey, * PRemapCfgKey; 53 | 54 | typedef enum RemapCfgOverride { 55 | RemapCfgOverrideAutoDetect, 56 | RemapCfgOverrideEnable, 57 | RemapCfgOverrideDisable 58 | } RemapCfgOverride, * PRemapCfgOverride; 59 | 60 | typedef enum RemapCfgKeyState { 61 | RemapCfgKeyStateNoDetect, 62 | RemapCfgKeyStateEnforce, 63 | RemapCfgKeyStateEnforceNot 64 | } RemapCfgKeyState, * PRemapCfgKeyState; 65 | 66 | typedef struct RemapCfg { 67 | RemapCfgKeyState LeftCtrl; 68 | RemapCfgKeyState LeftAlt; 69 | RemapCfgKeyState Search; 70 | RemapCfgKeyState Assistant; 71 | RemapCfgKeyState LeftShift; 72 | RemapCfgKeyState RightCtrl; 73 | RemapCfgKeyState RightAlt; 74 | RemapCfgKeyState RightShift; 75 | RemapCfgKey originalKey; 76 | BOOLEAN remapVivaldiToFnKeys; 77 | RemapCfgKey remappedKey; 78 | RemapCfgKey additionalKeys[8]; 79 | } RemapCfg, * PRemapCfg; 80 | 81 | typedef struct RemapCfgs { 82 | UINT32 magic; 83 | UINT32 remappings; 84 | BOOLEAN FlipSearchAndAssistantOnPixelbook; 85 | RemapCfgOverride HasAssistantKey; 86 | RemapCfgOverride IsNonChromeEC; 87 | RemapCfg cfg[1]; 88 | } RemapCfgs, * PRemapCfgs; 89 | #include 90 | 91 | typedef struct KeyStruct { 92 | USHORT MakeCode; 93 | USHORT Flags; 94 | USHORT InternalFlags; 95 | } KeyStruct, * PKeyStruct; 96 | 97 | typedef struct RemappedKeyStruct { 98 | struct KeyStruct origKey; 99 | struct KeyStruct remappedKey; 100 | } RemappedKeyStruct, * PRemappedKeyStruct; 101 | 102 | #define MAX_CURRENT_KEYS 20 103 | 104 | class VivaldiTester { 105 | UINT8 legacyTopRowKeys[10]; 106 | UINT8 legacyVivaldi[10]; 107 | 108 | UINT8 functionRowCount; 109 | KeyStruct functionRowKeys[16]; 110 | 111 | PRemapCfgs remapCfgs; 112 | 113 | BOOLEAN LeftCtrlPressed; 114 | BOOLEAN LeftAltPressed; 115 | BOOLEAN LeftShiftPressed; 116 | BOOLEAN AssistantPressed; 117 | BOOLEAN SearchPressed; 118 | 119 | BOOLEAN RightCtrlPressed; 120 | BOOLEAN RightAltPressed; 121 | BOOLEAN RightShiftPressed; 122 | 123 | KeyStruct currentKeys[MAX_CURRENT_KEYS]; 124 | KeyStruct lastKeyPressed; 125 | int numKeysPressed = 0; 126 | 127 | RemappedKeyStruct remappedKeys[MAX_CURRENT_KEYS]; 128 | int numRemaps; 129 | 130 | void updateKey(KeyStruct key); 131 | 132 | BOOLEAN addRemap(RemappedKeyStruct remap); 133 | void garbageCollect(); 134 | 135 | BOOLEAN checkKey(KEYBOARD_INPUT_DATA key, KeyStruct report[MAX_CURRENT_KEYS]); 136 | BOOLEAN addKey(KEYBOARD_INPUT_DATA key, KEYBOARD_INPUT_DATA data[MAX_CURRENT_KEYS]); 137 | 138 | INT32 IdxOfFnKey(RemapCfgKey originalKey); 139 | 140 | void RemapLoaded(KEYBOARD_INPUT_DATA report[MAX_CURRENT_KEYS], KEYBOARD_INPUT_DATA dataBefore[MAX_CURRENT_KEYS], KEYBOARD_INPUT_DATA dataAfter[MAX_CURRENT_KEYS]); 141 | 142 | public: 143 | VivaldiTester(); 144 | void ServiceCallback(PKEYBOARD_INPUT_DATA InputDataStart, PKEYBOARD_INPUT_DATA InputDataEnd, PULONG InputDataConsumed); 145 | }; 146 | 147 | #define filterExt this 148 | #define DbgPrint printf 149 | 150 | VivaldiTester::VivaldiTester() { 151 | const UINT8 legacyVivaldi[] = { 152 | VIVALDI_BACK, VIVALDI_FWD, VIVALDI_REFRESH, VIVALDI_FULLSCREEN, VIVALDI_OVERVIEW, VIVALDI_BRIGHTNESSDN, VIVALDI_BRIGHTNESSUP, VIVALDI_MUTE, VIVALDI_VOLDN, VIVALDI_VOLUP 153 | }; 154 | 155 | const UINT8 legacyVivaldiPixelbook[] = { 156 | VIVALDI_BACK, VIVALDI_REFRESH, VIVALDI_FULLSCREEN, VIVALDI_OVERVIEW, VIVALDI_BRIGHTNESSDN, VIVALDI_BRIGHTNESSUP, VIVALDI_PLAYPAUSE, VIVALDI_MUTE, VIVALDI_VOLDN, VIVALDI_VOLUP 157 | }; 158 | 159 | filterExt->numKeysPressed = 0; 160 | RtlZeroMemory(&filterExt->currentKeys, sizeof(filterExt->currentKeys)); 161 | RtlZeroMemory(&filterExt->lastKeyPressed, sizeof(filterExt->lastKeyPressed)); 162 | 163 | RtlZeroMemory(&filterExt->remappedKeys, sizeof(filterExt->remappedKeys)); 164 | filterExt->numRemaps = 0; 165 | 166 | filterExt->functionRowCount = 0; 167 | RtlZeroMemory(&filterExt->functionRowKeys, sizeof(filterExt->functionRowKeys)); 168 | 169 | RtlCopyMemory(&filterExt->legacyTopRowKeys, &fnKeys_set1, sizeof(filterExt->legacyTopRowKeys)); 170 | RtlCopyMemory(&filterExt->legacyVivaldi, &legacyVivaldi, sizeof(filterExt->legacyVivaldi)); 171 | 172 | /*filterExt->functionRowCount = sizeof(filterExt->legacyVivaldi); 173 | for (int i = 0; i < sizeof(filterExt->legacyVivaldi); i++) { 174 | filterExt->functionRowKeys[i].MakeCode = filterExt->legacyVivaldi[i]; 175 | filterExt->functionRowKeys[i].Flags |= KEY_E0; 176 | }*/ 177 | 178 | filterExt->functionRowCount = 13; 179 | UINT8 jinlon_keys[] = {VIVALDI_BACK, VIVALDI_REFRESH, VIVALDI_FULLSCREEN, VIVALDI_OVERVIEW, VIVALDI_SNAPSHOT, 180 | VIVALDI_BRIGHTNESSDN, VIVALDI_BRIGHTNESSUP, VIVALDI_KBD_BKLIGHT_DOWN, VIVALDI_KBD_BKLIGHT_UP, VIVALDI_PLAYPAUSE, 181 | VIVALDI_MUTE, VIVALDI_VOLDN, VIVALDI_VOLUP}; 182 | for (int i = 0; i < sizeof(jinlon_keys); i++) { 183 | filterExt->functionRowKeys[i].MakeCode = jinlon_keys[i]; 184 | filterExt->functionRowKeys[i].Flags |= KEY_E0; 185 | } 186 | 187 | { //Generate wilco keys 188 | size_t cfgSizeWilco = offsetof(RemapCfgs, cfg) + sizeof(RemapCfg) * 12; 189 | PRemapCfgs wilcoCfgs = (PRemapCfgs)malloc(cfgSizeWilco); 190 | RtlZeroMemory(wilcoCfgs, cfgSizeWilco); 191 | 192 | //Begin map wilco keys (Fn key and delete keys present, so minimal mappings) 193 | 194 | wilcoCfgs->magic = REMAP_CFG_MAGIC; 195 | wilcoCfgs->FlipSearchAndAssistantOnPixelbook = TRUE; 196 | wilcoCfgs->HasAssistantKey = RemapCfgOverrideAutoDetect; 197 | wilcoCfgs->IsNonChromeEC = RemapCfgOverrideAutoDetect; 198 | wilcoCfgs->remappings = 12; 199 | 200 | //Map Fullscreen -> F11 201 | 202 | wilcoCfgs->cfg[0].LeftCtrl = RemapCfgKeyStateNoDetect; 203 | wilcoCfgs->cfg[0].LeftShift = RemapCfgKeyStateNoDetect; 204 | wilcoCfgs->cfg[0].originalKey.MakeCode = WILCO_FULLSCREEN; 205 | wilcoCfgs->cfg[0].originalKey.Flags = KEY_E0; 206 | wilcoCfgs->cfg[0].remappedKey.MakeCode = fnKeys_set1[10]; 207 | 208 | //Map Overview -> Windows + Tab 209 | 210 | wilcoCfgs->cfg[1].LeftCtrl = RemapCfgKeyStateNoDetect; 211 | wilcoCfgs->cfg[1].LeftShift = RemapCfgKeyStateEnforceNot; 212 | wilcoCfgs->cfg[1].Search = RemapCfgKeyStateEnforceNot; 213 | wilcoCfgs->cfg[1].originalKey.MakeCode = WILCO_OVERVIEW; 214 | wilcoCfgs->cfg[1].originalKey.Flags = KEY_E0; 215 | wilcoCfgs->cfg[1].remappedKey.MakeCode = 0x0F; 216 | wilcoCfgs->cfg[1].additionalKeys[0].MakeCode = K_LWIN; 217 | wilcoCfgs->cfg[1].additionalKeys[0].Flags = KEY_E0; 218 | 219 | wilcoCfgs->cfg[2].LeftCtrl = RemapCfgKeyStateNoDetect; 220 | wilcoCfgs->cfg[2].LeftShift = RemapCfgKeyStateEnforceNot; 221 | wilcoCfgs->cfg[2].Search = RemapCfgKeyStateEnforce; 222 | wilcoCfgs->cfg[2].originalKey.MakeCode = WILCO_OVERVIEW; 223 | wilcoCfgs->cfg[2].originalKey.Flags = KEY_E0; 224 | wilcoCfgs->cfg[2].remappedKey.MakeCode = 0x0F; 225 | 226 | //Map Shift + Overview -> Windows + Shift + S 227 | 228 | wilcoCfgs->cfg[3].LeftCtrl = RemapCfgKeyStateNoDetect; 229 | wilcoCfgs->cfg[3].LeftShift = RemapCfgKeyStateEnforce; 230 | wilcoCfgs->cfg[3].Search = RemapCfgKeyStateEnforceNot; 231 | wilcoCfgs->cfg[3].originalKey.MakeCode = WILCO_OVERVIEW; 232 | wilcoCfgs->cfg[3].originalKey.Flags = KEY_E0; 233 | wilcoCfgs->cfg[3].remappedKey.MakeCode = 0x1F; 234 | wilcoCfgs->cfg[3].additionalKeys[0].MakeCode = K_LWIN; 235 | wilcoCfgs->cfg[3].additionalKeys[0].Flags = KEY_E0; 236 | 237 | wilcoCfgs->cfg[4].LeftCtrl = RemapCfgKeyStateNoDetect; 238 | wilcoCfgs->cfg[4].LeftShift = RemapCfgKeyStateEnforce; 239 | wilcoCfgs->cfg[4].Search = RemapCfgKeyStateEnforce; 240 | wilcoCfgs->cfg[4].originalKey.MakeCode = WILCO_OVERVIEW; 241 | wilcoCfgs->cfg[4].originalKey.Flags = KEY_E0; 242 | wilcoCfgs->cfg[4].remappedKey.MakeCode = 0x1F; 243 | 244 | //Map Wilco Brightness -> Vivaldi Brightness 245 | wilcoCfgs->cfg[5].LeftCtrl = RemapCfgKeyStateNoDetect; 246 | wilcoCfgs->cfg[5].LeftShift = RemapCfgKeyStateEnforceNot; 247 | wilcoCfgs->cfg[5].Search = RemapCfgKeyStateNoDetect; 248 | wilcoCfgs->cfg[5].originalKey.MakeCode = WILCO_BRIGHTNESSDN; 249 | wilcoCfgs->cfg[5].originalKey.Flags = KEY_E0; 250 | wilcoCfgs->cfg[5].remappedKey.MakeCode = VIVALDI_BRIGHTNESSDN; 251 | wilcoCfgs->cfg[5].remappedKey.Flags = KEY_E0; 252 | 253 | wilcoCfgs->cfg[6].LeftCtrl = RemapCfgKeyStateNoDetect; 254 | wilcoCfgs->cfg[6].LeftShift = RemapCfgKeyStateEnforceNot; 255 | wilcoCfgs->cfg[6].Search = RemapCfgKeyStateNoDetect; 256 | wilcoCfgs->cfg[6].originalKey.MakeCode = WILCO_BRIGHTNESSUP; 257 | wilcoCfgs->cfg[6].originalKey.Flags = KEY_E0; 258 | wilcoCfgs->cfg[6].remappedKey.MakeCode = VIVALDI_BRIGHTNESSUP; 259 | wilcoCfgs->cfg[6].remappedKey.Flags = KEY_E0; 260 | 261 | //Map Shift + Wilco Brightness -> Vivaldi Keyboard Brightness 262 | 263 | wilcoCfgs->cfg[7].LeftCtrl = RemapCfgKeyStateNoDetect; 264 | wilcoCfgs->cfg[7].LeftShift = RemapCfgKeyStateEnforce; 265 | wilcoCfgs->cfg[7].Search = RemapCfgKeyStateNoDetect; 266 | wilcoCfgs->cfg[7].originalKey.MakeCode = WILCO_BRIGHTNESSDN; 267 | wilcoCfgs->cfg[7].originalKey.Flags = KEY_E0; 268 | wilcoCfgs->cfg[7].remappedKey.MakeCode = VIVALDI_KBD_BKLIGHT_DOWN; 269 | wilcoCfgs->cfg[7].remappedKey.Flags = KEY_E0; 270 | 271 | wilcoCfgs->cfg[8].LeftCtrl = RemapCfgKeyStateNoDetect; 272 | wilcoCfgs->cfg[8].LeftShift = RemapCfgKeyStateEnforce; 273 | wilcoCfgs->cfg[8].Search = RemapCfgKeyStateNoDetect; 274 | wilcoCfgs->cfg[8].originalKey.MakeCode = WILCO_BRIGHTNESSUP; 275 | wilcoCfgs->cfg[8].originalKey.Flags = KEY_E0; 276 | wilcoCfgs->cfg[8].remappedKey.MakeCode = VIVALDI_KBD_BKLIGHT_UP; 277 | wilcoCfgs->cfg[8].remappedKey.Flags = KEY_E0; 278 | 279 | //Map Project -> Windows + P 280 | 281 | wilcoCfgs->cfg[9].LeftCtrl = RemapCfgKeyStateNoDetect; 282 | wilcoCfgs->cfg[9].LeftShift = RemapCfgKeyStateNoDetect; 283 | wilcoCfgs->cfg[9].Search = RemapCfgKeyStateEnforceNot; 284 | wilcoCfgs->cfg[9].originalKey.MakeCode = WILCO_PROJECT; 285 | wilcoCfgs->cfg[9].originalKey.Flags = KEY_E0; 286 | wilcoCfgs->cfg[9].remappedKey.MakeCode = 0x19; 287 | wilcoCfgs->cfg[9].additionalKeys[0].MakeCode = K_LWIN; 288 | wilcoCfgs->cfg[9].additionalKeys[0].Flags = KEY_E0; 289 | 290 | wilcoCfgs->cfg[10].LeftCtrl = RemapCfgKeyStateNoDetect; 291 | wilcoCfgs->cfg[10].LeftShift = RemapCfgKeyStateNoDetect; 292 | wilcoCfgs->cfg[10].Search = RemapCfgKeyStateEnforce; 293 | wilcoCfgs->cfg[10].originalKey.MakeCode = WILCO_PROJECT; 294 | wilcoCfgs->cfg[10].originalKey.Flags = KEY_E0; 295 | wilcoCfgs->cfg[10].remappedKey.MakeCode = 0x19; 296 | 297 | //Map Assistant -> Caps Lock (Search was remapped to assistant) 298 | wilcoCfgs->cfg[11].LeftCtrl = RemapCfgKeyStateNoDetect; 299 | wilcoCfgs->cfg[11].LeftShift = RemapCfgKeyStateNoDetect; 300 | wilcoCfgs->cfg[11].Search = RemapCfgKeyStateNoDetect; 301 | wilcoCfgs->cfg[11].originalKey.MakeCode = K_ASSISTANT; 302 | wilcoCfgs->cfg[11].originalKey.Flags = KEY_E0; 303 | wilcoCfgs->cfg[11].remappedKey.MakeCode = 0x3A; 304 | 305 | FILE* dumpedSettingsFile; 306 | if (fopen_s(&dumpedSettingsFile, "croskbsettings-wilco.bin", "wb") == 0) { 307 | fwrite(wilcoCfgs, 1, cfgSizeWilco, dumpedSettingsFile); 308 | fclose(dumpedSettingsFile); 309 | 310 | DbgPrint("Wrote wilco settings to croskbsettings-wilco.bin!\n"); 311 | } 312 | else { 313 | DbgPrint("Warning: Failed to write settings for croskeyboard4 (wilco)! Check that your permissions are correct!"); 314 | } 315 | 316 | free(wilcoCfgs); 317 | } 318 | 319 | 320 | size_t cfgSize = offsetof(RemapCfgs, cfg) + sizeof(RemapCfg) * 40; 321 | 322 | if (offsetof(RemapCfgs, cfg) != 17) { 323 | DbgPrint("Warning: RemapCfgs prefix size is incorrect. Your settings file may not work in croskeyboard4!\n"); 324 | } 325 | if (sizeof(RemapCfg) != 73) { 326 | DbgPrint("Warning: RemapCfg size is incorrect. Your settings file may not work in croskeyboard4!\n"); 327 | } 328 | 329 | PRemapCfgs remapCfgs = (PRemapCfgs)malloc(cfgSize); 330 | RtlZeroMemory(remapCfgs, cfgSize); 331 | 332 | //Begin map vivalid keys (without Ctrl) to F# keys 333 | 334 | remapCfgs->magic = REMAP_CFG_MAGIC; 335 | remapCfgs->FlipSearchAndAssistantOnPixelbook = TRUE; 336 | remapCfgs->HasAssistantKey = RemapCfgOverrideAutoDetect; 337 | remapCfgs->IsNonChromeEC = RemapCfgOverrideAutoDetect; 338 | remapCfgs->remappings = 40; 339 | 340 | //Begin map vivalid keys (without Ctrl) to F# keys 341 | 342 | remapCfgs->cfg[0].LeftCtrl = RemapCfgKeyStateEnforceNot; 343 | remapCfgs->cfg[0].originalKey.MakeCode = VIVALDI_BACK; 344 | remapCfgs->cfg[0].originalKey.Flags = KEY_E0; 345 | remapCfgs->cfg[0].remapVivaldiToFnKeys = TRUE; 346 | 347 | remapCfgs->cfg[1].LeftCtrl = RemapCfgKeyStateEnforceNot; 348 | remapCfgs->cfg[1].originalKey.MakeCode = VIVALDI_FWD; 349 | remapCfgs->cfg[1].originalKey.Flags = KEY_E0; 350 | remapCfgs->cfg[1].remapVivaldiToFnKeys = TRUE; 351 | 352 | remapCfgs->cfg[2].LeftCtrl = RemapCfgKeyStateEnforceNot; 353 | remapCfgs->cfg[2].originalKey.MakeCode = VIVALDI_REFRESH; 354 | remapCfgs->cfg[2].originalKey.Flags = KEY_E0; 355 | remapCfgs->cfg[2].remapVivaldiToFnKeys = TRUE; 356 | 357 | remapCfgs->cfg[3].LeftCtrl = RemapCfgKeyStateEnforceNot; 358 | remapCfgs->cfg[3].originalKey.MakeCode = VIVALDI_FULLSCREEN; 359 | remapCfgs->cfg[3].originalKey.Flags = KEY_E0; 360 | remapCfgs->cfg[3].remapVivaldiToFnKeys = TRUE; 361 | 362 | remapCfgs->cfg[4].LeftCtrl = RemapCfgKeyStateEnforceNot; 363 | remapCfgs->cfg[4].originalKey.MakeCode = VIVALDI_OVERVIEW; 364 | remapCfgs->cfg[4].originalKey.Flags = KEY_E0; 365 | remapCfgs->cfg[4].remapVivaldiToFnKeys = TRUE; 366 | 367 | remapCfgs->cfg[5].LeftCtrl = RemapCfgKeyStateEnforceNot; 368 | remapCfgs->cfg[5].originalKey.MakeCode = VIVALDI_SNAPSHOT; 369 | remapCfgs->cfg[5].originalKey.Flags = KEY_E0; 370 | remapCfgs->cfg[5].remapVivaldiToFnKeys = TRUE; 371 | 372 | remapCfgs->cfg[6].LeftCtrl = RemapCfgKeyStateEnforceNot; 373 | remapCfgs->cfg[6].originalKey.MakeCode = VIVALDI_BRIGHTNESSDN; 374 | remapCfgs->cfg[6].originalKey.Flags = KEY_E0; 375 | remapCfgs->cfg[6].remapVivaldiToFnKeys = TRUE; 376 | 377 | remapCfgs->cfg[7].LeftCtrl = RemapCfgKeyStateEnforceNot; 378 | remapCfgs->cfg[7].originalKey.MakeCode = VIVALDI_BRIGHTNESSUP; 379 | remapCfgs->cfg[7].originalKey.Flags = KEY_E0; 380 | remapCfgs->cfg[7].remapVivaldiToFnKeys = TRUE; 381 | 382 | remapCfgs->cfg[8].LeftCtrl = RemapCfgKeyStateEnforceNot; 383 | remapCfgs->cfg[8].originalKey.MakeCode = VIVALDI_PRIVACY_TOGGLE; 384 | remapCfgs->cfg[8].originalKey.Flags = KEY_E0; 385 | remapCfgs->cfg[8].remapVivaldiToFnKeys = TRUE; 386 | 387 | remapCfgs->cfg[9].LeftCtrl = RemapCfgKeyStateEnforceNot; 388 | remapCfgs->cfg[9].originalKey.MakeCode = VIVALDI_KBD_BKLIGHT_DOWN; 389 | remapCfgs->cfg[9].originalKey.Flags = KEY_E0; 390 | remapCfgs->cfg[9].remapVivaldiToFnKeys = TRUE; 391 | 392 | remapCfgs->cfg[10].LeftCtrl = RemapCfgKeyStateEnforceNot; 393 | remapCfgs->cfg[10].originalKey.MakeCode = VIVALDI_KBD_BKLIGHT_UP; 394 | remapCfgs->cfg[10].originalKey.Flags = KEY_E0; 395 | remapCfgs->cfg[10].remapVivaldiToFnKeys = TRUE; 396 | 397 | remapCfgs->cfg[11].LeftCtrl = RemapCfgKeyStateEnforceNot; 398 | remapCfgs->cfg[11].originalKey.MakeCode = VIVALDI_KBD_BKLIGHT_TOGGLE; 399 | remapCfgs->cfg[11].originalKey.Flags = KEY_E0; 400 | remapCfgs->cfg[11].remapVivaldiToFnKeys = TRUE; 401 | 402 | remapCfgs->cfg[12].LeftCtrl = RemapCfgKeyStateEnforceNot; 403 | remapCfgs->cfg[12].originalKey.MakeCode = VIVALDI_PLAYPAUSE; 404 | remapCfgs->cfg[12].originalKey.Flags = KEY_E0; 405 | remapCfgs->cfg[12].remapVivaldiToFnKeys = TRUE; 406 | 407 | remapCfgs->cfg[13].LeftCtrl = RemapCfgKeyStateEnforceNot; 408 | remapCfgs->cfg[13].originalKey.MakeCode = VIVALDI_MUTE; 409 | remapCfgs->cfg[13].originalKey.Flags = KEY_E0; 410 | remapCfgs->cfg[13].remapVivaldiToFnKeys = TRUE; 411 | 412 | remapCfgs->cfg[14].LeftCtrl = RemapCfgKeyStateEnforceNot; 413 | remapCfgs->cfg[14].originalKey.MakeCode = VIVALDI_VOLDN; 414 | remapCfgs->cfg[14].originalKey.Flags = KEY_E0; 415 | remapCfgs->cfg[14].remapVivaldiToFnKeys = TRUE; 416 | 417 | remapCfgs->cfg[15].LeftCtrl = RemapCfgKeyStateEnforceNot; 418 | remapCfgs->cfg[15].originalKey.MakeCode = VIVALDI_VOLUP; 419 | remapCfgs->cfg[15].originalKey.Flags = KEY_E0; 420 | remapCfgs->cfg[15].remapVivaldiToFnKeys = TRUE; 421 | 422 | remapCfgs->cfg[16].LeftCtrl = RemapCfgKeyStateEnforceNot; 423 | remapCfgs->cfg[16].originalKey.MakeCode = VIVALDI_NEXT_TRACK; 424 | remapCfgs->cfg[16].originalKey.Flags = KEY_E0; 425 | remapCfgs->cfg[16].remapVivaldiToFnKeys = TRUE; 426 | 427 | remapCfgs->cfg[17].LeftCtrl = RemapCfgKeyStateEnforceNot; 428 | remapCfgs->cfg[17].originalKey.MakeCode = VIVALDI_PREV_TRACK; 429 | remapCfgs->cfg[17].originalKey.Flags = KEY_E0; 430 | remapCfgs->cfg[17].remapVivaldiToFnKeys = TRUE; 431 | 432 | remapCfgs->cfg[18].LeftCtrl = RemapCfgKeyStateEnforceNot; 433 | remapCfgs->cfg[18].originalKey.MakeCode = VIVALDI_MICMUTE; 434 | remapCfgs->cfg[18].originalKey.Flags = KEY_E0; 435 | remapCfgs->cfg[18].remapVivaldiToFnKeys = TRUE; 436 | 437 | //Map Ctrl + Alt + Backspace -> Ctrl + Alt + Delete 438 | 439 | remapCfgs->cfg[19].LeftCtrl = RemapCfgKeyStateEnforce; 440 | remapCfgs->cfg[19].LeftAlt = RemapCfgKeyStateEnforce; 441 | remapCfgs->cfg[19].originalKey.MakeCode = K_BACKSP; 442 | remapCfgs->cfg[19].originalKey.Flags = 0; 443 | remapCfgs->cfg[19].remappedKey.MakeCode = K_DELETE; 444 | remapCfgs->cfg[19].remappedKey.Flags = KEY_E0; 445 | 446 | //Map Ctrl + Backspace -> Delete 447 | 448 | remapCfgs->cfg[20].LeftCtrl = RemapCfgKeyStateEnforce; 449 | remapCfgs->cfg[20].LeftAlt = RemapCfgKeyStateEnforceNot; 450 | remapCfgs->cfg[20].originalKey.MakeCode = K_BACKSP; 451 | remapCfgs->cfg[20].originalKey.Flags = 0; 452 | remapCfgs->cfg[20].remappedKey.MakeCode = K_DELETE; 453 | remapCfgs->cfg[20].remappedKey.Flags = KEY_E0; 454 | remapCfgs->cfg[20].additionalKeys[0].MakeCode = K_LCTRL; 455 | remapCfgs->cfg[20].additionalKeys[0].Flags = KEY_BREAK; 456 | 457 | //Map Ctrl + Fullscreen -> F11 458 | 459 | remapCfgs->cfg[21].LeftCtrl = RemapCfgKeyStateEnforce; 460 | remapCfgs->cfg[21].LeftShift = RemapCfgKeyStateEnforceNot; 461 | remapCfgs->cfg[21].originalKey.MakeCode = VIVALDI_FULLSCREEN; 462 | remapCfgs->cfg[21].originalKey.Flags = KEY_E0; 463 | remapCfgs->cfg[21].remappedKey.MakeCode = fnKeys_set1[10]; 464 | remapCfgs->cfg[21].additionalKeys[0].MakeCode = K_LCTRL; 465 | remapCfgs->cfg[21].additionalKeys[0].Flags = KEY_BREAK; 466 | 467 | //Map Ctrl + Shift + Fullscreen -> Windows + P 468 | 469 | remapCfgs->cfg[22].LeftCtrl = RemapCfgKeyStateEnforce; 470 | remapCfgs->cfg[22].LeftShift = RemapCfgKeyStateEnforce; 471 | remapCfgs->cfg[22].Search = RemapCfgKeyStateEnforceNot; 472 | remapCfgs->cfg[22].originalKey.MakeCode = VIVALDI_FULLSCREEN; 473 | remapCfgs->cfg[22].originalKey.Flags = KEY_E0; 474 | remapCfgs->cfg[22].remappedKey.MakeCode = 0x19; 475 | remapCfgs->cfg[22].additionalKeys[0].MakeCode = K_LCTRL; 476 | remapCfgs->cfg[22].additionalKeys[0].Flags = KEY_BREAK; 477 | remapCfgs->cfg[22].additionalKeys[1].MakeCode = K_LSHFT; 478 | remapCfgs->cfg[22].additionalKeys[1].Flags = KEY_BREAK; 479 | remapCfgs->cfg[22].additionalKeys[2].MakeCode = K_LWIN; 480 | remapCfgs->cfg[22].additionalKeys[2].Flags = KEY_E0; 481 | 482 | remapCfgs->cfg[23].LeftCtrl = RemapCfgKeyStateEnforce; 483 | remapCfgs->cfg[23].LeftShift = RemapCfgKeyStateEnforce; 484 | remapCfgs->cfg[23].Search = RemapCfgKeyStateEnforce; 485 | remapCfgs->cfg[23].originalKey.MakeCode = VIVALDI_FULLSCREEN; 486 | remapCfgs->cfg[23].originalKey.Flags = KEY_E0; 487 | remapCfgs->cfg[23].remappedKey.MakeCode = 0x19; 488 | remapCfgs->cfg[23].additionalKeys[0].MakeCode = K_LCTRL; 489 | remapCfgs->cfg[23].additionalKeys[0].Flags = KEY_BREAK; 490 | remapCfgs->cfg[23].additionalKeys[1].MakeCode = K_LSHFT; 491 | remapCfgs->cfg[23].additionalKeys[1].Flags = KEY_BREAK; 492 | 493 | //Map Ctrl + Overview -> Windows + Tab 494 | 495 | remapCfgs->cfg[24].LeftCtrl = RemapCfgKeyStateEnforce; 496 | remapCfgs->cfg[24].LeftShift = RemapCfgKeyStateEnforceNot; 497 | remapCfgs->cfg[24].Search = RemapCfgKeyStateEnforceNot; 498 | remapCfgs->cfg[24].originalKey.MakeCode = VIVALDI_OVERVIEW; 499 | remapCfgs->cfg[24].originalKey.Flags = KEY_E0; 500 | remapCfgs->cfg[24].remappedKey.MakeCode = 0x0F; 501 | remapCfgs->cfg[24].additionalKeys[0].MakeCode = K_LCTRL; 502 | remapCfgs->cfg[24].additionalKeys[0].Flags = KEY_BREAK; 503 | remapCfgs->cfg[24].additionalKeys[1].MakeCode = K_LWIN; 504 | remapCfgs->cfg[24].additionalKeys[1].Flags = KEY_E0; 505 | 506 | remapCfgs->cfg[25].LeftCtrl = RemapCfgKeyStateEnforce; 507 | remapCfgs->cfg[25].LeftShift = RemapCfgKeyStateEnforceNot; 508 | remapCfgs->cfg[25].Search = RemapCfgKeyStateEnforce; 509 | remapCfgs->cfg[25].originalKey.MakeCode = VIVALDI_OVERVIEW; 510 | remapCfgs->cfg[25].originalKey.Flags = KEY_E0; 511 | remapCfgs->cfg[25].remappedKey.MakeCode = 0x0F; 512 | remapCfgs->cfg[25].additionalKeys[0].MakeCode = K_LCTRL; 513 | remapCfgs->cfg[25].additionalKeys[0].Flags = KEY_BREAK; 514 | 515 | //Map Ctrl + Shift + Overview -> Windows + Shift + S 516 | 517 | remapCfgs->cfg[26].LeftCtrl = RemapCfgKeyStateEnforce; 518 | remapCfgs->cfg[26].LeftShift = RemapCfgKeyStateEnforce; 519 | remapCfgs->cfg[26].Search = RemapCfgKeyStateEnforceNot; 520 | remapCfgs->cfg[26].originalKey.MakeCode = VIVALDI_OVERVIEW; 521 | remapCfgs->cfg[26].originalKey.Flags = KEY_E0; 522 | remapCfgs->cfg[26].remappedKey.MakeCode = 0x1F; 523 | remapCfgs->cfg[26].additionalKeys[0].MakeCode = K_LCTRL; 524 | remapCfgs->cfg[26].additionalKeys[0].Flags = KEY_BREAK; 525 | remapCfgs->cfg[26].additionalKeys[1].MakeCode = K_LWIN; 526 | remapCfgs->cfg[26].additionalKeys[1].Flags = KEY_E0; 527 | 528 | remapCfgs->cfg[27].LeftCtrl = RemapCfgKeyStateEnforce; 529 | remapCfgs->cfg[27].LeftShift = RemapCfgKeyStateEnforce; 530 | remapCfgs->cfg[27].Search = RemapCfgKeyStateEnforce; 531 | remapCfgs->cfg[27].originalKey.MakeCode = VIVALDI_OVERVIEW; 532 | remapCfgs->cfg[27].originalKey.Flags = KEY_E0; 533 | remapCfgs->cfg[27].remappedKey.MakeCode = 0x1F; 534 | remapCfgs->cfg[27].additionalKeys[0].MakeCode = K_LCTRL; 535 | remapCfgs->cfg[27].additionalKeys[0].Flags = KEY_BREAK; 536 | 537 | //Map Ctrl + Snapshot -> Windows + Shift + S 538 | 539 | remapCfgs->cfg[28].LeftCtrl = RemapCfgKeyStateEnforce; 540 | remapCfgs->cfg[28].LeftShift = RemapCfgKeyStateEnforceNot; 541 | remapCfgs->cfg[28].Search = RemapCfgKeyStateEnforceNot; 542 | remapCfgs->cfg[28].originalKey.MakeCode = VIVALDI_SNAPSHOT; 543 | remapCfgs->cfg[28].originalKey.Flags = KEY_E0; 544 | remapCfgs->cfg[28].remappedKey.MakeCode = 0x1F; 545 | remapCfgs->cfg[28].additionalKeys[0].MakeCode = K_LCTRL; 546 | remapCfgs->cfg[28].additionalKeys[0].Flags = KEY_BREAK; 547 | remapCfgs->cfg[28].additionalKeys[1].MakeCode = K_LWIN; 548 | remapCfgs->cfg[28].additionalKeys[1].Flags = KEY_E0; 549 | remapCfgs->cfg[28].additionalKeys[2].MakeCode = K_LSHFT; 550 | 551 | remapCfgs->cfg[29].LeftCtrl = RemapCfgKeyStateEnforce; 552 | remapCfgs->cfg[29].LeftShift = RemapCfgKeyStateEnforceNot; 553 | remapCfgs->cfg[29].Search = RemapCfgKeyStateEnforce; 554 | remapCfgs->cfg[29].originalKey.MakeCode = VIVALDI_SNAPSHOT; 555 | remapCfgs->cfg[29].originalKey.Flags = KEY_E0; 556 | remapCfgs->cfg[29].remappedKey.MakeCode = 0x1F; 557 | remapCfgs->cfg[29].additionalKeys[0].MakeCode = K_LCTRL; 558 | remapCfgs->cfg[29].additionalKeys[0].Flags = KEY_BREAK; 559 | remapCfgs->cfg[29].additionalKeys[1].MakeCode = K_LSHFT; 560 | 561 | remapCfgs->cfg[30].LeftCtrl = RemapCfgKeyStateEnforce; 562 | remapCfgs->cfg[30].LeftShift = RemapCfgKeyStateEnforce; 563 | remapCfgs->cfg[30].Search = RemapCfgKeyStateEnforceNot; 564 | remapCfgs->cfg[30].originalKey.MakeCode = VIVALDI_SNAPSHOT; 565 | remapCfgs->cfg[30].originalKey.Flags = KEY_E0; 566 | remapCfgs->cfg[30].remappedKey.MakeCode = 0x1F; 567 | remapCfgs->cfg[30].additionalKeys[0].MakeCode = K_LCTRL; 568 | remapCfgs->cfg[30].additionalKeys[0].Flags = KEY_BREAK; 569 | remapCfgs->cfg[30].additionalKeys[1].MakeCode = K_LWIN; 570 | remapCfgs->cfg[30].additionalKeys[1].Flags = KEY_E0; 571 | 572 | remapCfgs->cfg[31].LeftCtrl = RemapCfgKeyStateEnforce; 573 | remapCfgs->cfg[31].LeftShift = RemapCfgKeyStateEnforce; 574 | remapCfgs->cfg[31].Search = RemapCfgKeyStateEnforce; 575 | remapCfgs->cfg[31].originalKey.MakeCode = VIVALDI_SNAPSHOT; 576 | remapCfgs->cfg[31].originalKey.Flags = KEY_E0; 577 | remapCfgs->cfg[31].remappedKey.MakeCode = 0x1F; 578 | remapCfgs->cfg[31].additionalKeys[0].MakeCode = K_LCTRL; 579 | remapCfgs->cfg[31].additionalKeys[0].Flags = KEY_BREAK; 580 | 581 | //Ctrl + Alt + Brightness -> Ctrl + Alt + KB Brightness 582 | 583 | remapCfgs->cfg[32].LeftCtrl = RemapCfgKeyStateEnforce; 584 | remapCfgs->cfg[32].LeftAlt = RemapCfgKeyStateEnforce; 585 | remapCfgs->cfg[32].originalKey.MakeCode = VIVALDI_BRIGHTNESSDN; 586 | remapCfgs->cfg[32].originalKey.Flags = KEY_E0; 587 | remapCfgs->cfg[32].remappedKey.MakeCode = VIVALDI_KBD_BKLIGHT_DOWN; 588 | remapCfgs->cfg[32].remappedKey.Flags = KEY_E0; 589 | 590 | remapCfgs->cfg[33].LeftCtrl = RemapCfgKeyStateEnforce; 591 | remapCfgs->cfg[33].LeftAlt = RemapCfgKeyStateEnforce; 592 | remapCfgs->cfg[33].originalKey.MakeCode = VIVALDI_BRIGHTNESSUP; 593 | remapCfgs->cfg[33].originalKey.Flags = KEY_E0; 594 | remapCfgs->cfg[33].remappedKey.MakeCode = VIVALDI_KBD_BKLIGHT_UP; 595 | remapCfgs->cfg[33].remappedKey.Flags = KEY_E0; 596 | 597 | //Ctrl + Left -> Home 598 | 599 | remapCfgs->cfg[34].LeftCtrl = RemapCfgKeyStateEnforce; 600 | remapCfgs->cfg[34].originalKey.MakeCode = K_LEFT; 601 | remapCfgs->cfg[34].originalKey.Flags = KEY_E0; 602 | remapCfgs->cfg[34].remappedKey.MakeCode = K_HOME; 603 | remapCfgs->cfg[34].remappedKey.Flags = KEY_E0; 604 | remapCfgs->cfg[34].additionalKeys[0].MakeCode = K_LCTRL; 605 | remapCfgs->cfg[34].additionalKeys[0].Flags = KEY_BREAK; 606 | 607 | //Ctrl + Right -> End 608 | 609 | remapCfgs->cfg[35].LeftCtrl = RemapCfgKeyStateEnforce; 610 | remapCfgs->cfg[35].originalKey.MakeCode = K_RIGHT; 611 | remapCfgs->cfg[35].originalKey.Flags = KEY_E0; 612 | remapCfgs->cfg[35].remappedKey.MakeCode = K_END; 613 | remapCfgs->cfg[35].remappedKey.Flags = KEY_E0; 614 | remapCfgs->cfg[35].additionalKeys[0].MakeCode = K_LCTRL; 615 | remapCfgs->cfg[35].additionalKeys[0].Flags = KEY_BREAK; 616 | 617 | //Ctrl + Up -> Page Up 618 | 619 | remapCfgs->cfg[36].LeftCtrl = RemapCfgKeyStateEnforce; 620 | remapCfgs->cfg[36].originalKey.MakeCode = K_UP; 621 | remapCfgs->cfg[36].originalKey.Flags = KEY_E0; 622 | remapCfgs->cfg[36].remappedKey.MakeCode = K_PGUP; 623 | remapCfgs->cfg[36].remappedKey.Flags = KEY_E0; 624 | remapCfgs->cfg[36].additionalKeys[0].MakeCode = K_LCTRL; 625 | remapCfgs->cfg[36].additionalKeys[0].Flags = KEY_BREAK; 626 | 627 | //Ctrl + Down -> Page Down 628 | 629 | remapCfgs->cfg[37].LeftCtrl = RemapCfgKeyStateEnforce; 630 | remapCfgs->cfg[37].originalKey.MakeCode = K_DOWN; 631 | remapCfgs->cfg[37].originalKey.Flags = KEY_E0; 632 | remapCfgs->cfg[37].remappedKey.MakeCode = K_PGDN; 633 | remapCfgs->cfg[37].remappedKey.Flags = KEY_E0; 634 | remapCfgs->cfg[37].additionalKeys[0].MakeCode = K_LCTRL; 635 | remapCfgs->cfg[37].additionalKeys[0].Flags = KEY_BREAK; 636 | 637 | //Lock -> Windows + L 638 | 639 | remapCfgs->cfg[38].Search = RemapCfgKeyStateEnforceNot; 640 | remapCfgs->cfg[38].originalKey.MakeCode = K_LOCK; 641 | remapCfgs->cfg[38].originalKey.Flags = 0; 642 | remapCfgs->cfg[38].remappedKey.MakeCode = 0x26; 643 | remapCfgs->cfg[38].additionalKeys[0].MakeCode = K_LWIN; 644 | remapCfgs->cfg[38].additionalKeys[0].Flags = KEY_E0; 645 | 646 | remapCfgs->cfg[39].Search = RemapCfgKeyStateEnforce; 647 | remapCfgs->cfg[39].originalKey.MakeCode = K_LOCK; 648 | remapCfgs->cfg[39].originalKey.Flags = 0; 649 | remapCfgs->cfg[39].remappedKey.MakeCode = 0x26; 650 | 651 | filterExt->remapCfgs = remapCfgs; 652 | 653 | DbgPrint("Initialized\n"); 654 | 655 | FILE* dumpedSettingsFile; 656 | if (fopen_s(&dumpedSettingsFile, "croskbsettings.bin", "wb") == 0) { 657 | fwrite(remapCfgs, 1, cfgSize, dumpedSettingsFile); 658 | fclose(dumpedSettingsFile); 659 | 660 | DbgPrint("Wrote active settings to croskbsettings.bin!\n"); 661 | } 662 | else { 663 | DbgPrint("Warning: Failed to write settings for croskeyboard4! Check that your permissions are correct!"); 664 | } 665 | } 666 | 667 | #undef filterExt 668 | #define devExt this 669 | 670 | void VivaldiTester::updateKey(KeyStruct data) { 671 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 672 | if (devExt->currentKeys[i].InternalFlags & INTFLAG_REMOVED) { 673 | RtlZeroMemory(&devExt->currentKeys[i], sizeof(devExt->currentKeys[0])); //Remove any keys marked to be removed 674 | } 675 | } 676 | 677 | KeyStruct origData = data; 678 | //Apply any remaps if they were done 679 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 680 | if (devExt->remappedKeys[i].origKey.MakeCode == data.MakeCode && 681 | devExt->remappedKeys[i].origKey.Flags == (data.Flags & KEY_TYPES)) { 682 | data.MakeCode = devExt->remappedKeys[i].remappedKey.MakeCode; 683 | data.Flags = devExt->remappedKeys[i].remappedKey.Flags | (data.Flags & ~KEY_TYPES); 684 | break; 685 | } 686 | } 687 | 688 | garbageCollect(); 689 | 690 | data.Flags = data.Flags & (KEY_TYPES | KEY_BREAK); 691 | if (data.Flags & KEY_BREAK) { //remove 692 | data.Flags = data.Flags & KEY_TYPES; 693 | origData.Flags = origData.Flags & KEY_TYPES; 694 | if (devExt->lastKeyPressed.MakeCode == data.MakeCode && 695 | devExt->lastKeyPressed.Flags == data.Flags) { 696 | RtlZeroMemory(&devExt->lastKeyPressed, sizeof(devExt->lastKeyPressed)); 697 | } 698 | 699 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 700 | if (devExt->currentKeys[i].MakeCode == data.MakeCode && 701 | devExt->currentKeys[i].Flags == data.Flags) { 702 | for (int j = 0; j < MAX_CURRENT_KEYS; j++) { //Remove any remaps if the original key is to be removed 703 | if (devExt->remappedKeys[j].origKey.MakeCode == origData.MakeCode && 704 | devExt->remappedKeys[j].origKey.Flags == origData.Flags) { 705 | RtlZeroMemory(&devExt->remappedKeys[j], sizeof(devExt->remappedKeys[0])); 706 | } 707 | } 708 | 709 | devExt->currentKeys[i].InternalFlags |= INTFLAG_REMOVED; 710 | } 711 | } 712 | } 713 | else { 714 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 715 | if (devExt->currentKeys[i].Flags == 0x00 && devExt->currentKeys[i].MakeCode == 0x00) { 716 | devExt->currentKeys[i] = data; 717 | devExt->currentKeys[i].InternalFlags |= INTFLAG_NEW; 718 | devExt->numKeysPressed++; 719 | devExt->lastKeyPressed = data; 720 | break; 721 | } 722 | else if (devExt->currentKeys[i].Flags == data.Flags && devExt->currentKeys[i].MakeCode == data.MakeCode) { 723 | break; 724 | } 725 | } 726 | } 727 | } 728 | 729 | BOOLEAN VivaldiTester::addRemap(RemappedKeyStruct remap) { 730 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 731 | if (devExt->remappedKeys[i].origKey.MakeCode == remap.origKey.MakeCode && 732 | devExt->remappedKeys[i].origKey.Flags == remap.remappedKey.Flags) { 733 | if (memcmp(&devExt->remappedKeys[i], &remap, sizeof(remap)) == 0) { 734 | return TRUE; //already exists 735 | } 736 | else { 737 | return FALSE; //existing remap exists but not the same 738 | } 739 | } 740 | } 741 | 742 | garbageCollect(); 743 | 744 | const RemappedKeyStruct emptyStruct = { 0 }; 745 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 746 | if (memcmp(&devExt->remappedKeys[i], &emptyStruct, sizeof(emptyStruct)) == 0) { 747 | devExt->remappedKeys[i] = remap; 748 | 749 | 750 | //Now apply remap 751 | for (int j = 0; j < MAX_CURRENT_KEYS; j++) { 752 | if (devExt->currentKeys[j].MakeCode == remap.origKey.MakeCode && 753 | devExt->currentKeys[j].Flags == remap.origKey.Flags) { 754 | devExt->currentKeys[j].MakeCode = remap.remappedKey.MakeCode; 755 | devExt->currentKeys[j].Flags = remap.remappedKey.Flags; 756 | break; 757 | } 758 | } 759 | 760 | return TRUE; 761 | } 762 | } 763 | return FALSE; //no slot found 764 | } 765 | 766 | void VivaldiTester::garbageCollect() { 767 | //Clear out any empty remap slots 768 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 769 | RemappedKeyStruct keyRemaps[MAX_CURRENT_KEYS] = { 0 }; 770 | const RemappedKeyStruct emptyStruct = { 0 }; 771 | int j = 0; 772 | for (int k = 0; k < MAX_CURRENT_KEYS; k++) { 773 | if (memcmp(&devExt->remappedKeys[k], &emptyStruct, sizeof(emptyStruct)) != 0) { 774 | keyRemaps[j] = devExt->remappedKeys[k]; 775 | j++; 776 | } 777 | } 778 | devExt->numRemaps = j; 779 | RtlCopyMemory(&devExt->remappedKeys, keyRemaps, sizeof(keyRemaps)); 780 | } 781 | 782 | //Clear out any empty key slots 783 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 784 | KeyStruct keyCodes[MAX_CURRENT_KEYS] = { 0 }; 785 | int j = 0; 786 | for (int k = 0; k < MAX_CURRENT_KEYS; k++) { 787 | if (devExt->currentKeys[k].Flags != 0 || 788 | devExt->currentKeys[k].MakeCode != 0) { 789 | keyCodes[j] = devExt->currentKeys[k]; 790 | j++; 791 | } 792 | } 793 | devExt->numKeysPressed = j; 794 | RtlCopyMemory(&devExt->currentKeys, keyCodes, sizeof(keyCodes)); 795 | } 796 | } 797 | 798 | UINT8 MapHIDKeys(KEYBOARD_INPUT_DATA report[MAX_CURRENT_KEYS], int* reportSize) { 799 | UINT8 flag = 0; 800 | for (int i = 0; i < *reportSize; i++) { 801 | if ((report[i].Flags & KEY_TYPES) == KEY_E0) { 802 | switch (report->MakeCode) { 803 | case VIVALDI_BRIGHTNESSDN: 804 | if (!(report[i].Flags & KEY_BREAK)) 805 | flag |= CROSKBHID_BRIGHTNESS_DN; 806 | break; 807 | case VIVALDI_BRIGHTNESSUP: 808 | if (!(report[i].Flags & KEY_BREAK)) 809 | flag |= CROSKBHID_BRIGHTNESS_UP; 810 | break; 811 | case VIVALDI_KBD_BKLIGHT_DOWN: 812 | if (!(report[i].Flags & KEY_BREAK)) 813 | flag |= CROSKBHID_KBLT_DN; 814 | break; 815 | case VIVALDI_KBD_BKLIGHT_UP: 816 | if (!(report[i].Flags & KEY_BREAK)) 817 | flag |= CROSKBHID_KBLT_UP; 818 | break; 819 | case VIVALDI_KBD_BKLIGHT_TOGGLE: 820 | if (!(report[i].Flags & KEY_BREAK)) 821 | flag |= CROSKBHID_KBLT_TOGGLE; 822 | break; 823 | default: 824 | continue; 825 | } 826 | report[i].MakeCode = 0; 827 | report[i].Flags = 0; 828 | } 829 | } 830 | 831 | //GC the new Report 832 | KEYBOARD_INPUT_DATA newReport[MAX_CURRENT_KEYS]; 833 | int newSize = 0; 834 | for (int i = 0; i < *reportSize; i++) { 835 | if (report[i].Flags != 0 || report[i].MakeCode != 0) { 836 | newReport[newSize] = report[i]; 837 | newSize++; 838 | } 839 | } 840 | 841 | RtlCopyMemory(report, newReport, sizeof(newReport[0]) * newSize); 842 | *reportSize = newSize; 843 | 844 | return flag; 845 | } 846 | 847 | BOOLEAN VivaldiTester::checkKey(KEYBOARD_INPUT_DATA key, KeyStruct report[MAX_CURRENT_KEYS]) { 848 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 849 | if (report[i].MakeCode == key.MakeCode && 850 | report[i].Flags == (key.Flags & KEY_TYPES)) { 851 | return TRUE; 852 | } 853 | } 854 | return FALSE; 855 | } 856 | 857 | BOOLEAN VivaldiTester::addKey(KEYBOARD_INPUT_DATA key, KEYBOARD_INPUT_DATA data[MAX_CURRENT_KEYS]) { 858 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 859 | if (data[i].MakeCode == key.MakeCode && 860 | data[i].Flags == (key.Flags & KEY_TYPES)) { 861 | return data[i].Flags == key.Flags; //If both contain the same bit value of BREAK, we're ok. Otherwise we're not 862 | } 863 | else if (data[i].MakeCode == 0 && data[i].Flags == 0) { 864 | data[i] = key; 865 | return TRUE; 866 | } 867 | } 868 | return FALSE; 869 | } 870 | 871 | BOOLEAN validateBool(RemapCfgKeyState keyState, BOOLEAN containerBOOL) { 872 | if (keyState == RemapCfgKeyStateNoDetect){ 873 | return TRUE; 874 | } 875 | 876 | if ((keyState == RemapCfgKeyStateEnforce && containerBOOL) || 877 | (keyState == RemapCfgKeyStateEnforceNot && !containerBOOL)) { 878 | return TRUE; 879 | } 880 | 881 | return FALSE; 882 | } 883 | 884 | INT32 VivaldiTester::IdxOfFnKey(RemapCfgKey originalKey) { 885 | if (originalKey.Flags != KEY_E0) { 886 | return -1; 887 | } 888 | 889 | for (int i = 0; i < devExt->functionRowCount; i++) { 890 | if (devExt->functionRowKeys[i].MakeCode == originalKey.MakeCode) { 891 | return i; 892 | } 893 | } 894 | 895 | return -1; 896 | } 897 | 898 | void VivaldiTester::RemapLoaded(KEYBOARD_INPUT_DATA data[MAX_CURRENT_KEYS], KEYBOARD_INPUT_DATA dataBefore[MAX_CURRENT_KEYS], KEYBOARD_INPUT_DATA dataAfter[MAX_CURRENT_KEYS]) { 899 | if (!devExt->remapCfgs || devExt->remapCfgs->magic != REMAP_CFG_MAGIC) 900 | return; 901 | 902 | for (int i = 0; i < devExt->numKeysPressed; i++) { 903 | for (UINT32 j = 0; j < devExt->remapCfgs->remappings; j++) { 904 | RemapCfg cfg = devExt->remapCfgs->cfg[j]; 905 | 906 | if (!validateBool(cfg.LeftCtrl, devExt->LeftCtrlPressed)) 907 | continue; 908 | if (!validateBool(cfg.LeftAlt, devExt->LeftAltPressed)) 909 | continue; 910 | if (!validateBool(cfg.LeftShift, devExt->LeftShiftPressed)) 911 | continue; 912 | if (!validateBool(cfg.Assistant, devExt->AssistantPressed)) 913 | continue; 914 | if (!validateBool(cfg.Search, devExt->SearchPressed)) 915 | continue; 916 | if (!validateBool(cfg.RightCtrl, devExt->RightCtrlPressed)) 917 | continue; 918 | if (!validateBool(cfg.RightAlt, devExt->RightAltPressed)) 919 | continue; 920 | if (!validateBool(cfg.RightShift, devExt->RightShiftPressed)) 921 | continue; 922 | 923 | if (data[i].MakeCode == cfg.originalKey.MakeCode && 924 | (cfg.originalKey.Flags & KEY_TYPES) == (data[i].Flags & KEY_TYPES)) { 925 | 926 | RemappedKeyStruct remappedStruct = { 0 }; 927 | remappedStruct.origKey.MakeCode = data[i].MakeCode; 928 | remappedStruct.origKey.Flags = data[i].Flags; 929 | 930 | INT32 fnKeyIdx = IdxOfFnKey(cfg.originalKey); 931 | if (cfg.remapVivaldiToFnKeys && fnKeyIdx != -1) { 932 | remappedStruct.remappedKey.MakeCode = fnKeys_set1[fnKeyIdx]; 933 | remappedStruct.remappedKey.Flags = 0; 934 | if (addRemap(remappedStruct)) { 935 | data[i].Flags &= ~KEY_TYPES; 936 | data[i].MakeCode = fnKeys_set1[fnKeyIdx]; 937 | } 938 | } 939 | else { 940 | remappedStruct.remappedKey.MakeCode = cfg.remappedKey.MakeCode; 941 | remappedStruct.remappedKey.Flags = (cfg.remappedKey.Flags & KEY_TYPES); 942 | if (addRemap(remappedStruct)) { 943 | data[i].Flags = (cfg.remappedKey.Flags & KEY_TYPES); 944 | data[i].MakeCode = cfg.remappedKey.MakeCode; 945 | } 946 | 947 | for (int k = 0; k < sizeof(cfg.additionalKeys) / sizeof(cfg.additionalKeys[0]); k++) { 948 | if ((cfg.additionalKeys[k].Flags & (KEY_TYPES | KEY_BREAK)) == 0 && cfg.additionalKeys[k].MakeCode == 0) { 949 | break; 950 | } 951 | 952 | KEYBOARD_INPUT_DATA addData = { 0 }; 953 | addData.MakeCode = cfg.additionalKeys[k].MakeCode; 954 | addData.Flags = cfg.additionalKeys[k].Flags & (KEY_TYPES | KEY_BREAK); 955 | addKey(addData, dataBefore); 956 | 957 | KEYBOARD_INPUT_DATA removeData = { 0 }; 958 | removeData.MakeCode = addData.MakeCode; 959 | removeData.Flags = cfg.additionalKeys[k].Flags & KEY_TYPES; 960 | if ((addData.Flags & KEY_BREAK) == 0) { 961 | removeData.Flags |= KEY_BREAK; 962 | } 963 | addKey(removeData, dataAfter); 964 | } 965 | } 966 | 967 | break; 968 | } 969 | } 970 | } 971 | } 972 | 973 | void VivaldiTester::ServiceCallback(PKEYBOARD_INPUT_DATA InputDataStart, PKEYBOARD_INPUT_DATA InputDataEnd, PULONG InputDataConsumed) { 974 | PKEYBOARD_INPUT_DATA pData; 975 | for (pData = InputDataStart; pData != InputDataEnd; pData++) { //First loop -> Refresh Modifier Keys and Change Legacy Keys to vivaldi bindings 976 | if ((pData->Flags & KEY_TYPES) == 0) { 977 | switch (pData->MakeCode) 978 | { 979 | case K_LCTRL: //L CTRL 980 | if ((pData->Flags & KEY_BREAK) == 0) { 981 | devExt->LeftCtrlPressed = TRUE; 982 | } 983 | else { 984 | devExt->LeftCtrlPressed = FALSE; 985 | } 986 | break; 987 | case K_LALT: //L Alt 988 | if ((pData->Flags & KEY_BREAK) == 0) { 989 | devExt->LeftAltPressed = TRUE; 990 | } 991 | else { 992 | devExt->LeftAltPressed = FALSE; 993 | } 994 | break; 995 | case K_LSHFT: //L Shift 996 | if ((pData->Flags & KEY_BREAK) == 0) { 997 | devExt->LeftShiftPressed = TRUE; 998 | } 999 | else { 1000 | devExt->LeftShiftPressed = FALSE; 1001 | } 1002 | break; 1003 | case K_RSHFT: //R Shift 1004 | if ((pData->Flags & KEY_BREAK) == 0) { 1005 | devExt->RightShiftPressed = TRUE; 1006 | } 1007 | else { 1008 | devExt->RightShiftPressed = FALSE; 1009 | } 1010 | break; 1011 | default: 1012 | for (int i = 0; i < sizeof(devExt->legacyTopRowKeys); i++) { 1013 | if (pData->MakeCode == devExt->legacyTopRowKeys[i]) { 1014 | pData->MakeCode = devExt->legacyVivaldi[i]; 1015 | pData->Flags |= KEY_E0; //All legacy vivaldi upgrades use E0 modifier 1016 | } 1017 | } 1018 | 1019 | break; 1020 | } 1021 | } 1022 | if ((pData->Flags & KEY_TYPES) == KEY_E0) { 1023 | switch (pData->MakeCode) 1024 | { 1025 | case K_ASSISTANT: //Assistant Key 1026 | if ((pData->Flags & KEY_BREAK) == 0) { 1027 | devExt->AssistantPressed = TRUE; 1028 | } 1029 | else { 1030 | devExt->AssistantPressed = FALSE; 1031 | } 1032 | break; 1033 | case K_LWIN: //Search Key 1034 | if ((pData->Flags & KEY_BREAK) == 0) { 1035 | devExt->SearchPressed = TRUE; 1036 | } 1037 | else { 1038 | devExt->SearchPressed = FALSE; 1039 | } 1040 | break; 1041 | case K_RCTRL: //R CTRL 1042 | if ((pData->Flags & KEY_BREAK) == 0) { 1043 | devExt->RightCtrlPressed = TRUE; 1044 | } 1045 | else { 1046 | devExt->RightCtrlPressed = FALSE; 1047 | } 1048 | break; 1049 | case K_RALT: //R Alt 1050 | if ((pData->Flags & KEY_BREAK) == 0) { 1051 | devExt->RightAltPressed = TRUE; 1052 | } 1053 | else { 1054 | devExt->RightAltPressed = FALSE; 1055 | } 1056 | break; 1057 | 1058 | } 1059 | } 1060 | } 1061 | 1062 | { 1063 | //Now make the data HID-like for easier handling 1064 | ULONG i = 0; 1065 | for (i = 0; i < (InputDataEnd - InputDataStart); i++) { 1066 | KeyStruct key = { 0 }; 1067 | key.MakeCode = InputDataStart[i].MakeCode; 1068 | key.Flags = InputDataStart[i].Flags; 1069 | updateKey(key); 1070 | } 1071 | *InputDataConsumed = i; 1072 | } 1073 | 1074 | KEYBOARD_INPUT_DATA newReport[MAX_CURRENT_KEYS] = { 0 }; 1075 | //Add new keys 1076 | for (int i = 0, j = 0; i < devExt->numKeysPressed; i++) { //Prepare new report for remapper to sort through 1077 | if (devExt->currentKeys[i].InternalFlags & INTFLAG_NEW) { 1078 | newReport[j].MakeCode = devExt->currentKeys[i].MakeCode; 1079 | newReport[j].Flags = devExt->currentKeys[i].Flags; 1080 | devExt->currentKeys[i].InternalFlags &= ~INTFLAG_NEW; 1081 | j++; 1082 | } 1083 | } 1084 | 1085 | KEYBOARD_INPUT_DATA preReport[MAX_CURRENT_KEYS] = { 0 }; 1086 | KEYBOARD_INPUT_DATA postReport[MAX_CURRENT_KEYS] = { 0 }; 1087 | 1088 | //Do whichever remap was chosen 1089 | //RemapPassthrough(newReport, preReport, postReport); 1090 | //RemapLegacy(newReport, preReport, postReport); 1091 | RemapLoaded(newReport, preReport, postReport); 1092 | 1093 | //Remove any empty keys 1094 | int newReportKeysPresent = 0; 1095 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 1096 | if (newReport[i].Flags != 0 || 1097 | newReport[i].MakeCode != 0) { 1098 | newReport[newReportKeysPresent] = newReport[i]; 1099 | newReportKeysPresent++; 1100 | } 1101 | } 1102 | 1103 | for (int i = newReportKeysPresent; i < MAX_CURRENT_KEYS; i++) { 1104 | RtlZeroMemory(&newReport[i], sizeof(newReport[i])); 1105 | } 1106 | 1107 | //Now add all the removed keys 1108 | int reportSize = newReportKeysPresent; 1109 | for (int i = 0; i < devExt->numKeysPressed; i++) { //Prepare new report for remapper to sort through 1110 | if (devExt->currentKeys[i].InternalFlags & INTFLAG_REMOVED) { 1111 | newReport[reportSize].MakeCode = devExt->currentKeys[i].MakeCode; 1112 | newReport[reportSize].Flags = devExt->currentKeys[i].Flags | KEY_BREAK; 1113 | reportSize++; 1114 | } 1115 | } 1116 | 1117 | //If empty report keys, add the last key (if present) 1118 | if (reportSize == 0 && (devExt->lastKeyPressed.MakeCode != 0 || devExt->lastKeyPressed.Flags != 0)) { 1119 | newReport[reportSize].MakeCode = devExt->lastKeyPressed.MakeCode; 1120 | newReport[reportSize].Flags = devExt->lastKeyPressed.Flags; 1121 | 1122 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 1123 | if (devExt->remappedKeys[i].origKey.MakeCode == devExt->lastKeyPressed.MakeCode && 1124 | devExt->remappedKeys[i].origKey.Flags == (devExt->lastKeyPressed.Flags & KEY_TYPES)) { 1125 | newReport[reportSize].MakeCode = devExt->remappedKeys[i].remappedKey.MakeCode; 1126 | newReport[reportSize].Flags = devExt->remappedKeys[i].remappedKey.Flags | (newReport[reportSize].Flags & ~KEY_TYPES); 1127 | break; 1128 | } 1129 | } 1130 | 1131 | reportSize++; 1132 | } 1133 | 1134 | //Now prepare the report 1135 | for (int i = 0; i < reportSize; i++) { 1136 | newReport[i].UnitId = InputDataStart[0].UnitId; 1137 | 1138 | //Always override Vivaldi Play/Pause to Windows native equivalent 1139 | if (newReport[i].MakeCode == VIVALDI_PLAYPAUSE && 1140 | (pData->Flags & (KEY_E0 | KEY_E1)) == KEY_E0) { 1141 | pData->MakeCode = 0x22; //Windows native Play / Pause Code 1142 | } 1143 | } 1144 | 1145 | UINT8 HIDFlag = MapHIDKeys(newReport, &reportSize); 1146 | 1147 | ULONG DataConsumed; 1148 | DbgPrint("\tLegacy Keys\n"); 1149 | if (InputDataEnd > InputDataStart) { 1150 | ReceiveKeys_Guarded(InputDataStart, InputDataEnd, &DataConsumed); 1151 | } 1152 | 1153 | DbgPrint("\tHID Consumer Keys: 0x%x\n", HIDFlag); 1154 | 1155 | DbgPrint("\tHID translated Keys\n"); 1156 | 1157 | { 1158 | int preReportSize = 0; 1159 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 1160 | if (preReport[i].Flags != 0 || preReport[i].MakeCode != 0) { 1161 | preReportSize++; 1162 | } 1163 | } 1164 | 1165 | if (preReportSize > 0) { 1166 | ReceiveKeys_Guarded(preReport, preReport + preReportSize, &DataConsumed); 1167 | } 1168 | } 1169 | 1170 | if (reportSize > 0) { 1171 | ReceiveKeys_Guarded(newReport, newReport + reportSize, &DataConsumed); 1172 | } 1173 | 1174 | { 1175 | int postReportSize = 0; 1176 | for (int i = 0; i < MAX_CURRENT_KEYS; i++) { 1177 | if (postReport[i].Flags != 0 || postReport[i].MakeCode != 0) { 1178 | postReportSize++; 1179 | } 1180 | } 1181 | 1182 | if (postReportSize > 0) { 1183 | ReceiveKeys_Guarded(postReport, postReport + postReportSize, &DataConsumed); 1184 | } 1185 | } 1186 | } 1187 | 1188 | int CompareKeys(const void *raw1, const void *raw2) { 1189 | PKEYBOARD_INPUT_DATA data1 = (PKEYBOARD_INPUT_DATA)raw1; 1190 | PKEYBOARD_INPUT_DATA data2 = (PKEYBOARD_INPUT_DATA)raw2; 1191 | return ((data1->MakeCode - data2->MakeCode) << 4) + 1192 | ((data2->Flags & KEY_TYPES - (data1->Flags & KEY_TYPES))); 1193 | } 1194 | 1195 | void ReceiveKeys_Guarded(PKEYBOARD_INPUT_DATA startPtr, PKEYBOARD_INPUT_DATA endPtr, PULONG InputDataConsumed) { 1196 | qsort(startPtr, endPtr - startPtr, sizeof(*startPtr), CompareKeys); 1197 | 1198 | ULONG consumedCount = 0; 1199 | 1200 | printf("\t\t==Frame Start==\n"); 1201 | for (ULONG i = 0; i < endPtr - startPtr; i++) { 1202 | printf("\t\t\tKey %d: Code 0x%x, Flags 0x%x\n", i, startPtr[i].MakeCode, startPtr[i].Flags); 1203 | consumedCount++; 1204 | } 1205 | printf("\t\t==Frame End==\n"); 1206 | 1207 | for (ULONG i = 0; i < (endPtr - 1) - startPtr; i++) { 1208 | assert(startPtr[i].MakeCode != startPtr[i + 1].MakeCode || 1209 | (startPtr[i].Flags & KEY_TYPES) != (startPtr[i + 1].Flags & KEY_TYPES)); 1210 | } 1211 | 1212 | *InputDataConsumed = consumedCount; 1213 | } 1214 | 1215 | void SubmitKeys_Guarded(VivaldiTester *test, PKEYBOARD_INPUT_DATA start, UINT32 count) { 1216 | PKEYBOARD_INPUT_DATA newData = (PKEYBOARD_INPUT_DATA)malloc(sizeof(KEYBOARD_INPUT_DATA) * count); 1217 | assert(newData != 0); 1218 | 1219 | RtlCopyMemory(newData, start, sizeof(KEYBOARD_INPUT_DATA) * count); 1220 | 1221 | ULONG consumedCount = 0; 1222 | test->ServiceCallback(newData, newData + count, &consumedCount); 1223 | 1224 | assert(consumedCount == count); //Weird breakage can happen if this isn't equal 1225 | free(newData); 1226 | } 1227 | 1228 | int main() 1229 | { 1230 | VivaldiTester test; 1231 | 1232 | KEYBOARD_INPUT_DATA testData[2]; 1233 | RtlZeroMemory(testData, sizeof(testData)); //Reset test data 1234 | 1235 | /*testData[0].MakeCode = K_LCTRL; 1236 | printf("Ctrl\n"); 1237 | SubmitKeys_Guarded(&test, testData, 1); 1238 | 1239 | printf("Ctrl Repeat\n"); 1240 | SubmitKeys_Guarded(&test, testData, 1); 1241 | 1242 | testData[0].MakeCode = VIVALDI_MUTE; 1243 | testData[0].Flags = KEY_E0; 1244 | printf("Mute\n"); 1245 | SubmitKeys_Guarded(&test, testData, 1); 1246 | 1247 | testData[0].Flags |= KEY_BREAK; 1248 | printf("Mute Release\n"); 1249 | SubmitKeys_Guarded(&test, testData, 1); 1250 | 1251 | testData[0].MakeCode = K_LCTRL; 1252 | testData[0].Flags = 0; 1253 | printf("Ctrl Repeat\n"); 1254 | SubmitKeys_Guarded(&test, testData, 1); 1255 | 1256 | testData[0].Flags |= KEY_BREAK; 1257 | printf("Ctrl Release\n"); 1258 | SubmitKeys_Guarded(&test, testData, 1); 1259 | 1260 | testData[0].MakeCode = VIVALDI_MUTE; 1261 | testData[0].Flags = KEY_E0; 1262 | printf("Mute\n"); 1263 | SubmitKeys_Guarded(&test, testData, 1); 1264 | 1265 | testData[0].Flags |= KEY_BREAK; 1266 | printf("Mute Release\n"); 1267 | SubmitKeys_Guarded(&test, testData, 1); 1268 | 1269 | RtlZeroMemory(testData, sizeof(testData)); //Reset test data 1270 | 1271 | testData[0].MakeCode = 0x1E; 1272 | testData[0].Flags = 0; 1273 | printf("A Press\n"); 1274 | SubmitKeys_Guarded(&test, testData, 1); 1275 | 1276 | printf("A Hold\n"); 1277 | SubmitKeys_Guarded(&test, testData, 1); 1278 | 1279 | printf("A Hold\n"); 1280 | SubmitKeys_Guarded(&test, testData, 1); 1281 | 1282 | testData[0].MakeCode = 0x1F; 1283 | testData[0].Flags = 0; 1284 | printf("S Press + A Hold\n"); 1285 | SubmitKeys_Guarded(&test, testData, 1); 1286 | 1287 | printf("S + A Hold\n"); 1288 | SubmitKeys_Guarded(&test, testData, 1); 1289 | 1290 | printf("S + A Hold\n"); 1291 | SubmitKeys_Guarded(&test, testData, 1); 1292 | 1293 | printf("S + A Hold\n"); 1294 | SubmitKeys_Guarded(&test, testData, 1); 1295 | 1296 | testData[0].MakeCode = 0x1E; 1297 | testData[0].Flags = KEY_BREAK; 1298 | printf("A Release\n"); 1299 | SubmitKeys_Guarded(&test, testData, 1); 1300 | 1301 | testData[0].MakeCode = 0x1F; 1302 | testData[0].Flags = 0; 1303 | printf("S Hold\n"); 1304 | SubmitKeys_Guarded(&test, testData, 1); 1305 | 1306 | printf("S Hold\n"); 1307 | SubmitKeys_Guarded(&test, testData, 1); 1308 | 1309 | testData[0].MakeCode = 0x1F; 1310 | testData[0].Flags = KEY_BREAK; 1311 | printf("S Release\n"); 1312 | SubmitKeys_Guarded(&test, testData, 1); 1313 | 1314 | RtlZeroMemory(testData, sizeof(testData)); //Reset test data 1315 | 1316 | testData[0].MakeCode = K_LCTRL; 1317 | printf("Ctrl\n"); 1318 | SubmitKeys_Guarded(&test, testData, 1); 1319 | 1320 | testData[0].MakeCode = K_LALT; 1321 | printf("Alt\n"); 1322 | SubmitKeys_Guarded(&test, testData, 1); 1323 | 1324 | testData[0].MakeCode = K_BACKSP; 1325 | printf("Backspace\n"); 1326 | SubmitKeys_Guarded(&test, testData, 1); 1327 | 1328 | testData[0].MakeCode = K_LCTRL; 1329 | testData[0].Flags = KEY_BREAK; 1330 | printf("Release Ctrl\n"); 1331 | SubmitKeys_Guarded(&test, testData, 1); 1332 | 1333 | testData[0].MakeCode = K_LALT; 1334 | testData[0].Flags = KEY_BREAK; 1335 | printf("Release Alt\n"); 1336 | SubmitKeys_Guarded(&test, testData, 1); 1337 | 1338 | testData[0].MakeCode = K_BACKSP; 1339 | testData[0].Flags = KEY_BREAK; 1340 | printf("Release Backspace\n"); 1341 | SubmitKeys_Guarded(&test, testData, 1); 1342 | 1343 | testData[0].MakeCode = K_BACKSP; 1344 | testData[0].Flags = 0; 1345 | printf("Backspace\n"); 1346 | SubmitKeys_Guarded(&test, testData, 1); 1347 | 1348 | testData[0].MakeCode = K_BACKSP; 1349 | testData[0].Flags = KEY_BREAK; 1350 | printf("Release Backspace\n"); 1351 | SubmitKeys_Guarded(&test, testData, 1); 1352 | 1353 | testData[0].MakeCode = K_LCTRL; 1354 | testData[0].Flags = 0; 1355 | printf("Ctrl\n"); 1356 | SubmitKeys_Guarded(&test, testData, 1); 1357 | 1358 | testData[0].MakeCode = VIVALDI_BRIGHTNESSUP; 1359 | testData[0].Flags = KEY_E0; 1360 | printf("Brightness Up\n"); 1361 | SubmitKeys_Guarded(&test, testData, 1); 1362 | 1363 | testData[0].MakeCode = VIVALDI_BRIGHTNESSUP; 1364 | testData[0].Flags = KEY_E0 | KEY_BREAK; 1365 | printf("Release Brightness Up\n"); 1366 | SubmitKeys_Guarded(&test, testData, 1); 1367 | 1368 | testData[0].MakeCode = K_LCTRL; 1369 | testData[0].Flags = KEY_BREAK; 1370 | printf("Release Ctrl\n"); 1371 | SubmitKeys_Guarded(&test, testData, 1);*/ 1372 | 1373 | testData[0].MakeCode = VIVALDI_VOLUP; 1374 | testData[0].Flags = KEY_E0; 1375 | printf("Volume Up\n"); 1376 | SubmitKeys_Guarded(&test, testData, 1); 1377 | 1378 | testData[0].MakeCode = VIVALDI_VOLUP; 1379 | testData[0].Flags = KEY_E0 | KEY_BREAK; 1380 | printf("Release Volume Up\n"); 1381 | SubmitKeys_Guarded(&test, testData, 1); 1382 | } --------------------------------------------------------------------------------