diff --git a/.gitignore b/.gitignore index 40e8281..13d3003 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ test_build.rb test_run.rb .project test.rb +.idea \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/active-tab-highlighter-v2.xml b/.idea/active-tab-highlighter-v2.xml new file mode 100644 index 0000000..bdaf016 --- /dev/null +++ b/.idea/active-tab-highlighter-v2.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/.idea/auto_click.iml b/.idea/auto_click.iml new file mode 100644 index 0000000..320af29 --- /dev/null +++ b/.idea/auto_click.iml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/deployment.xml b/.idea/deployment.xml new file mode 100644 index 0000000..18a6e04 --- /dev/null +++ b/.idea/deployment.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..b19fd24 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,67 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..081d4e1 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..051c6d7 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Gemfile b/Gemfile index a781486..cbe39d7 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ -source "http://rubygems.org" +source "https://rubygems.org" # Specify your gem's dependencies in auto_click.gemspec gemspec diff --git a/Gemfile.lock b/Gemfile.lock index 5c3c698..b204b40 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,14 +1,17 @@ PATH remote: . specs: - auto_click (0.1.0) + win_auto_click (2.0.0) GEM - remote: http://rubygems.org/ + remote: https://rubygems.org/ specs: PLATFORMS - x86-mingw32 + x64-mingw-ucrt DEPENDENCIES - auto_click! + win_auto_click! + +BUNDLED WITH + 2.5.5 diff --git a/README.rdoc b/README.rdoc index 4e66b5a..2671d86 100644 --- a/README.rdoc +++ b/README.rdoc @@ -23,9 +23,6 @@ To move the mouse cursor to 50,50 ( the top left corner is 0,0) and perform a do mouse_move(50,50) double_click - -To move the mouse cursor to 50,50 and perform a right click: - mouse_move(50,50) right_click @@ -206,51 +203,3 @@ you can construct a new instance of AutoClick and invoke the methods from the in - key_down(key_name) - key_up(key_name) - -== To Do List - -- Backward compatibility with 32-bit Ruby - -- Add options of movement speed of mouse so the cursor is actually "moving" instead of just show up at the destination instantly - -- GetWindow and GetWindowFocus Method - -- Refactor the ugly type(string) method - -- Use code block to implement modifier keys - -- More effective way to move mouse relative to current position - -== Change log -(for full change log please refer to the CHANGELOG file in the repository) - -- 0.5.0 Users have to explicitly use "include AutoClickMethods" to include the methods, add mouse_move_percentage and get_screen_resolution - -- 0.4.0 Fix the 64bit bug and Fixnum! bug - -- 0.3.0 Update to use DL Library - - -== License - -MIT license - -Copyright (C) 2010-2019 by Chungsang Tom Lam - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/auto_click.gemspec b/auto_click.gemspec index a4f1100..71c281c 100644 --- a/auto_click.gemspec +++ b/auto_click.gemspec @@ -1,26 +1,25 @@ # -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "auto_click/version" - Gem::Specification.new do |s| - s.name = "auto_click" - s.version = AutoClick::VERSION - s.platform = Gem::Platform::RUBY - s.authors = ["erinata"] - s.email = ["erinata@gmail.com"] - s.homepage = "https://github.com/erinata/auto_click" - s.summary = %q{Smulating mouse click, cursor movement and keystrokes} - s.description = %q{Provide several Ruby methods for simulating mouse click, cursor movement and keystrokes in Windows. + s.name = "auto_click" + s.version = AutoClick::VERSION + s.platform = Gem::Platform::RUBY + s.authors = ["erinata", "BrianPurgert"] + s.email = ["erinata@gmail.com", "brianpurgert2@gmail.com"] + s.homepage = "https://github.com/BrianPurgert/auto_click" + s.summary = %q{Smulating mouse click, cursor movement and keystrokes} + s.description = %q{this is a Fork of https://github.com/erinata/auto_click + Provide several Ruby methods for simulating mouse click, cursor movement and keystrokes in Windows. This gem use DL library and SendInput method so there is no dependency on FFI, AutoIt or Win32-api. Methods include mouse_move(x,y), left_click, right_click, type(string), mouse_scroll(steps), key_up, key_down...etc. - See https://github.com/erinata/auto_click for more details about instalation and usage. - (More control over mouse movement such as speed or locus will be implemented in future releases)} - - s.required_ruby_version = '>= 2.3.0' - - s.files = `git ls-files`.split("\n") - s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") - s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } - s.require_paths = ["lib"] - s.licenses = "MIT" + )} + s.required_ruby_version = '>= 2.3.0' + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") + s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) } + s.require_paths = ["lib"] + s.licenses = "MIT" end + + diff --git a/lib/auto_click.rb b/lib/auto_click.rb index 57a4ffa..bbb2c6b 100644 --- a/lib/auto_click.rb +++ b/lib/auto_click.rb @@ -2,370 +2,278 @@ require 'auto_click/input_structure' require 'auto_click/virtual_key' require 'auto_click/user32' - module AutoClickMethods - @@rightdown = InputStructure.mouse_input(0,0,0,0x0008) - @@rightup = InputStructure.mouse_input(0,0,0,0x0010) - @@leftdown = InputStructure.mouse_input(0,0,0,0x0002) - @@leftup = InputStructure.mouse_input(0,0,0,0x0004) - @@middledown = InputStructure.mouse_input(0,0,0,0x0020) - @@middleup = InputStructure.mouse_input(0,0,0,0x0040) + @@rightdown = InputStructure.mouse_input(0, 0, 0, 0x0008) + @@rightup = InputStructure.mouse_input(0, 0, 0, 0x0010) + @@leftdown = InputStructure.mouse_input(0, 0, 0, 0x0002) + @@leftup = InputStructure.mouse_input(0, 0, 0, 0x0004) + @@middledown = InputStructure.mouse_input(0, 0, 0, 0x0020) + @@middleup = InputStructure.mouse_input(0, 0, 0, 0x0040) + def send_input(inputs) + n = inputs.size + ptr = inputs.collect { |i| i.to_s }.join + User32.SendInput(n, ptr, inputs[0].size) + end - def send_input(inputs) - n = inputs.size - ptr = inputs.collect {|i| i.to_s}.join - User32.SendInput(n, ptr, inputs[0].size) - end + def get_screen_resolution + [User32.GetSystemMetrics(0), User32.GetSystemMetrics(1)] + end - def get_screen_resolution - [User32.GetSystemMetrics(0), User32.GetSystemMetrics(1)] - end + def mouse_move(x, y) + User32.SetCursorPos(x, y) + end - def mouse_move(x,y) - User32.SetCursorPos(x,y) - end + def mouse_move_percentage(x, y) + screen_resolution = get_screen_resolution + User32.SetCursorPos(screen_resolution[0] * x, screen_resolution[1] * y) + end - def mouse_move_percentage(x,y) - screen_resolution = get_screen_resolution() - User32.SetCursorPos(screen_resolution[0]*x, screen_resolution[1]*y) - end - - - def right_click - send_input( [@@rightdown, @@rightup] ) - end - - def left_click - send_input( [@@leftdown, @@leftup] ) - end - - def middle_click - send_input( [@@middledown, @@middleup] ) - end - - def mouse_down(button_name) - case button_name - when :right - send_input( [@@rightdown] ) - when :middle - send_input( [@@middledown] ) - else - send_input( [@@leftdown] ) - end - end - - def mouse_up(button_name) - case button_name - when :right - send_input( [@@rightup] ) - when :middle - send_input( [@@middleup] ) - else - send_input( [@@leftup] ) - end - end - - def double_click - left_click - left_click - end + def right_click + send_input([@@rightdown, @@rightup]) + end - ################# TEMP ##################### + def left_click + send_input([@@leftdown, @@leftup]) + end + def middle_click + send_input([@@middledown, @@middleup]) + end - @@rightdown32 = InputStructure.mouse_input_32(0,0,0,0x0008) - @@rightup32 = InputStructure.mouse_input_32(0,0,0,0x0010) - @@leftdown32 = InputStructure.mouse_input_32(0,0,0,0x0002) - @@leftup32 = InputStructure.mouse_input_32(0,0,0,0x0004) - @@middledown32 = InputStructure.mouse_input_32(0,0,0,0x0020) - @@middleup32 = InputStructure.mouse_input_32(0,0,0,0x0040) + def mouse_down(button_name) + case button_name + when :right + send_input([@@rightdown]) + when :middle + send_input([@@middledown]) + else + send_input([@@leftdown]) + end + end + def mouse_up(button_name) + case button_name + when :right + send_input([@@rightup]) + when :middle + send_input([@@middleup]) + else + send_input([@@leftup]) + end + end - def right_click_32 - send_input( [@@rightdown32, @@rightup32] ) - end - - def left_click_32 - send_input( [@@leftdown32, @@leftup32] ) - end - - def middle_click_32 - send_input( [@@middledown32, @@middleup32] ) - end - - def mouse_down_32(button_name) - case button_name - when :right - send_input( [@@rightdown32] ) - when :middle - send_input( [@@middledown32] ) - else - send_input( [@@leftdown32] ) - end - end - - def mouse_up_32(button_name) - case button_name - when :right - send_input( [@@rightup32] ) - when :middle - send_input( [@@middleup32] ) - else - send_input( [@@leftup32] ) - end - end - - def double_click_32 - left_click_32 - left_click_32 - end + def double_click + left_click + left_click + end + def cursor_position + point = " " * 8 + User32.GetCursorPos(point) + point.unpack('LL') + end - def left_drag_32(sx,sy,ex,ey) - mouse_move sx,sy - sleep 0.1 - send_input( [@@leftdown32] ) - sleep 0.1 - mouse_move ex,ey - sleep 0.1 - send_input( [@@leftup32] ) - sleep 0.1 - end - - def right_drag_32(sx,sy,ex,ey) - mouse_move sx,sy - sleep 0.1 - send_input( [@@rightdown32] ) - sleep 0.1 - mouse_move ex,ey - sleep 0.1 - send_input( [@@rightup32] ) - sleep 0.1 - end + def mouse_scroll(d) + scroll = InputStructure.mouse_input(0, 0, d * 120, 0x0800) + send_input([scroll]) + end - def key_stroke_32(key_name) - code=VirtualKey.code_from_name(key_name) - send_input([InputStructure.keyboard_input_32(code,0x0000), - InputStructure.keyboard_input_32(code,0x0002)]) - end - - def key_down_32(key_name) - code=VirtualKey.code_from_name(key_name) - send_input([InputStructure.keyboard_input_32(code,0x0000)]) - end - - def key_up_32(key_name) - code=VirtualKey.code_from_name(key_name) - send_input([InputStructure.keyboard_input_32(code,0x0002)]) - end + def left_drag(sx, sy, ex, ey) + mouse_move sx, sy + sleep 0.1 + send_input([@@leftdown]) + sleep 0.1 + mouse_move ex, ey + sleep 0.1 + send_input([@@leftup]) + sleep 0.1 + end -################# END TEMP ##################### - - def cursor_position - point = " " * 8 - User32.GetCursorPos(point) - point.unpack('LL') - end - - def mouse_scroll(d) - scroll = InputStructure.mouse_input(0,0,d*120,0x0800) - send_input( [scroll]) - end - + def right_drag(sx, sy, ex, ey) + mouse_move sx, sy + sleep 0.1 + send_input([@@rightdown]) + sleep 0.1 + mouse_move ex, ey + sleep 0.1 + send_input([@@rightup]) + sleep 0.1 + end - def left_drag(sx,sy,ex,ey) - mouse_move sx,sy - sleep 0.1 - send_input( [@@leftdown] ) - sleep 0.1 - mouse_move ex,ey - sleep 0.1 - send_input( [@@leftup] ) - sleep 0.1 - end - - def right_drag(sx,sy,ex,ey) - mouse_move sx,sy - sleep 0.1 - send_input( [@@rightdown] ) - sleep 0.1 - mouse_move ex,ey - sleep 0.1 - send_input( [@@rightup] ) - sleep 0.1 - end - - def key_stroke(key_name) - code=VirtualKey.code_from_name(key_name) - send_input([InputStructure.keyboard_input(code,0x0000), - InputStructure.keyboard_input(code,0x0002)]) - end - - def key_down(key_name) - code=VirtualKey.code_from_name(key_name) - send_input([InputStructure.keyboard_input(code,0x0000)]) - end - - def key_up(key_name) - code=VirtualKey.code_from_name(key_name) - send_input([InputStructure.keyboard_input(code,0x0002)]) - end - - def type(string) - key_stroke(:capslock) if get_key_state(:capslock)==1 - string=string.to_s - string.each_char do |c| - if ('a'..'z').include? c - key_stroke(c.to_sym) - elsif ('A'..'Z').include? c - key_down(:leftshift) - key_stroke(c.to_sym) - key_up(:leftshift) - elsif ('0'..'9').include? c - key_stroke(('num'+c).to_sym) - else - case c - when ' ' - key_stroke(:space) - when ';' - key_stroke(:semicolon) - when ':' - key_down(:leftshift) - key_stroke(:semicolon) - key_up(:leftshift) - when '=' - key_stroke(:equal) - when '+' - key_down(:leftshift) - key_stroke(:plus) - key_up(:leftshift) - when ',' - key_stroke(:comma) - when '<' - key_down(:leftshift) - key_stroke(:smallerthan) - key_up(:leftshift) - when '-' - key_stroke(:hyphen) - when '_' - key_down(:leftshift) - key_stroke(:underscore) - key_up(:leftshift) - when '.' - key_stroke(:period) - when '>' - key_down(:leftshift) - key_stroke(:greaterthan) - key_up(:leftshift) - when '/' - key_stroke(:slash) - when '?' - key_down(:leftshift) - key_stroke(:question) - key_up(:leftshift) - when '`' - key_stroke(:grave) - when '~' - key_down(:leftshift) - key_stroke(:tilde) - key_up(:leftshift) - when '/' - key_stroke(:slash) - when '?' - key_down(:leftshift) - key_stroke(:question) - key_up(:leftshift) - when '[' - key_stroke(:branket) - when '{' - key_down(:leftshift) - key_stroke(:branket) - key_up(:leftshift) - when ']' - key_stroke(:closebranket) - when '}' - key_down(:leftshift) - key_stroke(:closebranket) - key_up(:leftshift) - when '\\' # You need to esapce \ in the parameter string - key_stroke(:backslash) - when '|' - key_down(:leftshift) - key_stroke(:pipe) - key_up(:leftshift) - when '\'' # escape ' only for single quote string - key_stroke(:quote) - when '"' # escape " only for double quote string - key_down(:leftshift) - key_stroke(:doublequote) - key_up(:leftshift) - when '!' - key_down(:leftshift) - key_stroke(:num1) - key_up(:leftshift) - when '@' - key_down(:leftshift) - key_stroke(:num2) - key_up(:leftshift) - when '#' # The sharp sign need to be escape in single quote string - key_down(:leftshift) - key_stroke(:num3) - key_up(:leftshift) - when '$' - key_down(:leftshift) - key_stroke(:num4) - key_up(:leftshift) - when '%' - key_down(:leftshift) - key_stroke(:num5) - key_up(:leftshift) - when '^' - key_down(:leftshift) - key_stroke(:num6) - key_up(:leftshift) - when '&' - key_down(:leftshift) - key_stroke(:num7) - key_up(:leftshift) - when '*' - key_down(:leftshift) - key_stroke(:num8) - key_up(:leftshift) - when '(' - key_down(:leftshift) - key_stroke(:num9) - key_up(:leftshift) - when ')' - key_down(:leftshift) - key_stroke(:num0) - key_up(:leftshift) - end - - end - end - end - - def get_key_state(key_name) - code=VirtualKey.code_from_name(key_name) - User32.GetKeyState(code) - # For normal keys (such as a) - # When the key is down the value is -128 - # When the key is up the value is 0 - - # For toggle keys (such as capslock) - # When the cap key is down and the caplock is on the value is -127 - # When the cap key is down and the caplock is off the value is -128 - # When the cap key is Up and the caplock is on the value is 1 - # When the cap key is Up and the caplock is off the value is 0 - end -end + def key_stroke(*keys) + down_keys = keys.map do |key| + code = VirtualKey.code_from_name(key) + InputStructure.keyboard_input(code, 0x0000) + end + up_keys = keys.map do |key| + code = VirtualKey.code_from_name(key) + InputStructure.keyboard_input(code, 0x0002) + end + send_input(down_keys + up_keys) + end + def key_down(key_name) + code = VirtualKey.code_from_name(key_name) + send_input([InputStructure.keyboard_input(code, 0x0000)]) + end -# include AutoClick # This line allow auto include when the user require the gem + def key_up(key_name) + code = VirtualKey.code_from_name(key_name) + send_input([InputStructure.keyboard_input(code, 0x0002)]) + end -class AutoClick - include AutoClickMethods + def type(string) + key_stroke(:capslock) if get_key_state(:capslock) == 1 + string = string.to_s + string.each_char do |⌨| + if ('a'..'z').include? ⌨ + key_stroke(⌨.to_sym) + elsif ('A'..'Z').include? ⌨ + key_down(:leftshift) + key_stroke(⌨.to_sym) + key_up(:leftshift) + elsif ('0'..'9').include? ⌨ + key_stroke(('num' + ⌨).to_sym) + else + case ⌨ + when ' ' + key_stroke(:space) + when ';' + key_stroke(:semicolon) + when ':' + key_down(:leftshift) + key_stroke(:semicolon) + key_up(:leftshift) + when '=' + key_stroke(:equal) + when '+' + key_down(:leftshift) + key_stroke(:plus) + key_up(:leftshift) + when ',' + key_stroke(:comma) + when '<' + key_down(:leftshift) + key_stroke(:smallerthan) + key_up(:leftshift) + when '-' + key_stroke(:hyphen) + when '_' + key_down(:leftshift) + key_stroke(:underscore) + key_up(:leftshift) + when '.' + key_stroke(:period) + when '.' + key_stroke(:period) + when '>' + key_down(:leftshift) + key_stroke(:greaterthan) + key_up(:leftshift) + when '/' + key_stroke(:slash) + when '?' + key_down(:leftshift) + key_stroke(:question) + key_up(:leftshift) + when '`' + key_stroke(:grave) + when '~' + key_down(:leftshift) + key_stroke(:tilde) + key_up(:leftshift) + when '/' + key_stroke(:slash) + when '?' + key_down(:leftshift) + key_stroke(:question) + key_up(:leftshift) + when '[' + key_stroke(:branket) + when '{' + key_down(:leftshift) + key_stroke(:branket) + key_up(:leftshift) + when ']' + key_stroke(:closebranket) + when '}' + key_down(:leftshift) + key_stroke(:closebranket) + key_up(:leftshift) + when '\\' # You need to esapce \ in the parameter string + key_stroke(:backslash) + when '|' + key_down(:leftshift) + key_stroke(:pipe) + key_up(:leftshift) + when '\'' # escape ' only for single quote string + key_stroke(:quote) + when '"' # escape " only for double quote string + key_down(:leftshift) + key_stroke(:doublequote) + key_up(:leftshift) + when '!' + key_down(:leftshift) + key_stroke(:num1) + key_up(:leftshift) + when '@' + key_down(:leftshift) + key_stroke(:num2) + key_up(:leftshift) + when '#' # The sharp sign need to be escape in single quote string + key_down(:leftshift) + key_stroke(:num3) + key_up(:leftshift) + when '$' + key_down(:leftshift) + key_stroke(:num4) + key_up(:leftshift) + when '%' + key_down(:leftshift) + key_stroke(:num5) + key_up(:leftshift) + when '^' + key_down(:leftshift) + key_stroke(:num6) + key_up(:leftshift) + when '&' + key_down(:leftshift) + key_stroke(:num7) + key_up(:leftshift) + when '*' + key_down(:leftshift) + key_stroke(:num8) + key_up(:leftshift) + when '(' + key_down(:leftshift) + key_stroke(:num9) + key_up(:leftshift) + when ')' + key_down(:leftshift) + key_stroke(:num0) + key_up(:leftshift) + end + end + end + end + + def get_key_state(key_name) + code = VirtualKey.code_from_name(key_name) + User32.GetKeyState(code) + # For normal keys (such as a) + # When the key is down the value is -128 + # When the key is up the value is 0 + # For toggle keys (such as capslock) + # When the cap key is down and the caplock is on the value is -127 + # When the cap key is down and the caplock is off the value is -128 + # When the cap key is Up and the caplock is on the value is 1 + # When the cap key is Up and the caplock is off the value is 0 + end +end +# include AutoClick # This line allow auto include when the user require the gem +module AutoClick + include AutoClickMethods end diff --git a/lib/auto_click/input_structure.rb b/lib/auto_click/input_structure.rb index 567b9f6..c9882bb 100644 --- a/lib/auto_click/input_structure.rb +++ b/lib/auto_click/input_structure.rb @@ -1,40 +1,36 @@ module InputStructure + def self.mouse_input(dx, dy, mouse_data, dw_flags) + mi = Array.new(7, 0) + mi[0] = 0 + mi[1] = dx + mi[2] = dy + mi[3] = mouse_data + mi[4] = dw_flags + mi.pack('QLLLLQQ') + end - def self.mouse_input(dx,dy,mouse_data,dw_flags) - mi = Array.new(7, 0) - mi[0] = 0 - mi[1] = dx - mi[2] = dy - mi[3] = mouse_data - mi[4] = dw_flags - mi.pack('QLLLLQQ') - end - - def self.keyboard_input(wVk,dw_flags) - ki = Array.new(7, 0) - ki[0] = 1 - ki[1] = wVk - ki[2] = dw_flags - ki.pack('QLLLLQQ') - end + def self.keyboard_input(wVk, dw_flags) + ki = Array.new(7, 0) + ki[0] = 1 + ki[1] = wVk + ki[2] = dw_flags + ki.pack('QLLLLQQ') + end - def self.mouse_input_32(dx,dy,mouse_data,dw_flags) - mi = Array.new(7, 0) - mi[0] = 0 - mi[1] = dx - mi[2] = dy - mi[3] = mouse_data - mi[4] = dw_flags - mi.pack('LLLLLLL') - end - - def self.keyboard_input_32(wVk,dw_flags) - ki = Array.new(7, 0) - ki[0] = 1 - ki[1] = wVk - ki[2] = dw_flags - ki.pack('LLLLLLL') - end - - + # def self.mouse_input_32(dx, dy, mouse_data, dw_flags) + # mi = Array.new(7, 0) + # mi[0] = 0 + # mi[1] = dx + # mi[2] = dy + # mi[3] = mouse_data + # mi[4] = dw_flags + # mi.pack('LLLLLLL') + # end + # def self.keyboard_input_32(wVk, dw_flags) + # ki = Array.new(7, 0) + # ki[0] = 1 + # ki[1] = wVk + # ki[2] = dw_flags + # ki.pack('LLLLLLL') + # end end \ No newline at end of file diff --git a/lib/auto_click/user32.rb b/lib/auto_click/user32.rb index 124e1cc..9c06096 100644 --- a/lib/auto_click/user32.rb +++ b/lib/auto_click/user32.rb @@ -1,9 +1,9 @@ module User32 - extend Fiddle::Importer - dlload 'user32' - extern "int GetCursorPos(char*)" - extern "int SetCursorPos(int,int)" - extern "int SendInput(int,char*,int)" - extern "int GetKeyState(int)" - extern "int GetSystemMetrics(int)" + extend Fiddle::Importer + dlload 'user32' + extern "int GetCursorPos(char*)" + extern "int SetCursorPos(int,int)" + extern "int SendInput(int,char*,int)" + extern "int GetKeyState(int)" + extern "int GetSystemMetrics(int)" end diff --git a/lib/auto_click/version.rb b/lib/auto_click/version.rb index e6f36dd..3b2dd9c 100644 --- a/lib/auto_click/version.rb +++ b/lib/auto_click/version.rb @@ -1,3 +1,3 @@ module AutoClick - VERSION = "0.5.9" + VERSION = "2.0.0" end diff --git a/lib/auto_click/virtual_key.rb b/lib/auto_click/virtual_key.rb index 83c5551..549f9d5 100644 --- a/lib/auto_click/virtual_key.rb +++ b/lib/auto_click/virtual_key.rb @@ -1,530 +1,141 @@ module VirtualKey - def self.code_from_name(name) + KEYNAMES_TO_CODES = { + a: 0x41, + alt: 0x12, + alternate: 0x12, + app: 0x5D, + application: 0x5D, + b: 0x42, + back: 0x08, + backspace: 0x08, + c: 0x43, + cap: 0x14, + caplock: 0x14, + capslock: 0x14, + clear: 0x0C, + control: 0x11, + ctrl: 0x11, + d: 0x44, + del: 0x2E, + delete: 0x2E, + down: 0x28, + downarrow: 0x28, + downkey: 0x28, + e: 0x45, + end: 0x23, + enter: 0x0D, + esc: 0x1B, + escape: 0x1B, + exe: 0x2B, + execute: 0x2B, + f: 0x46, + f1: 0x70, + f10: 0x79, + f11: 0x7A, + f12: 0x7B, + f13: 0x7C, + f14: 0x7D, + f15: 0x7E, + f16: 0x7F, + f17: 0x80, + f18: 0x81, + f19: 0x82, + f2: 0x71, + f20: 0x83, + f21: 0x84, + f22: 0x85, + f23: 0x86, + f24: 0x87, + f3: 0x72, + f4: 0x73, + f5: 0x74, + f6: 0x75, + f7: 0x76, + f8: 0x77, + f9: 0x78, + g: 0x47, + h: 0x48, + help: 0x2F, + home: 0x24, + i: 0x49, + ins: 0x2D, + insert: 0x2D, + j: 0x4A, + k: 0x4B, + l: 0x4C, + left: 0x25, + leftarrow: 0x25, + leftkey: 0x25, + leftwin: 0x5B, + m: 0x4D, + n: 0x4E, + num0: 0x30, + num1: 0x31, + num2: 0x32, + num3: 0x33, + num4: 0x34, + num5: 0x35, + num6: 0x36, + num7: 0x37, + num8: 0x38, + num9: 0x39, + number0: 0x30, + number1: 0x31, + number2: 0x32, + number3: 0x33, + number4: 0x34, + number5: 0x35, + number6: 0x36, + number7: 0x37, + number8: 0x38, + number9: 0x39, + numlock: 0x90, + o: 0x4F, + p: 0x50, + pagedown: 0x22, + pageup: 0x21, + pause: 0x13, + print: 0x2A, + printscr: 0x2C, + printscreen: 0x2C, + q: 0x51, + r: 0x52, + return: 0x0D, + right: 0x27, + rightarrow: 0x27, + rightkey: 0x27, + rightwin: 0x5C, + s: 0x53, + scrolllock: 0x91, + select: 0x29, + shift: 0x10, + sleep: 0x5F, + space: 0x20, + spacebar: 0x20, + t: 0x54, + tab: 0x09, + u: 0x55, + up: 0x26, + uparrow: 0x26, + upkey: 0x26, + v: 0x56, + w: 0x57, + win: 0x5B, + windows: 0x5B, + x: 0x58, + y: 0x59, + z: 0x5A, + period: 0xBE, + periodkey: 0xBE, + comma: 0xBC, + commakey: 0xBC + }.freeze - if name.kind_of? Fixnum - return name - elsif name.kind_of? String - name=name.delete('_').delete('-').delete(' ') - end - name = name.to_sym.downcase - case name - #when - # 0x00S - #when - # 0x01 - #when - # 0x02 - #when - # 0x03 - #when - # 0x04 - #when - # 0x05 - #when - # 0x06 - #when - # 0x07 - when :back,:backspace - 0x08 - when :tab - 0x09 - #when - # 0x0A - #when - # 0x0B - when :clear - 0x0C - when :return,:enter - 0x0D - #when - # 0x0E - #when - # 0x0F - when :shift - 0x10 - when :ctrl,:control - 0x11 - when :alt,:alternate - 0x12 - when :pause - 0x13 - when :cap,:capslock,:caplock - 0x14 - #when - # 0x15 - #when - # 0x16 - #when - # 0x17 - #when - # 0x18 - #when - # 0x19 - #when - # 0x1A - when :esc,:escape - 0x1B - #when - # 0x1C - #when - # 0x1D - #when - # 0x1E - #when - # 0x1F - when :space,:spacebar - 0x20 - when :pageup - 0x21 - when :pagedown - 0x22 - when :end - 0x23 - when :home - 0x24 - when :left,:leftarrow,:leftkey - 0x25 - when :up,:uparrow,:upkey - 0x26 - when :right,:rightarrow,:rightkey - 0x27 - when :down,:downarrow,:downkey - 0x28 - when :select - 0x29 - when :print - 0x2A - when :exe,:execute - 0x2B - when :printscr,:printscreen - 0x2C - when :ins,:insert - 0x2D - when :del,:delete - 0x2E - when :help - 0x2F - when :num0,:number0 - 0x30 - when :num1,:number1 - 0x31 - when :num2,:number2 - 0x32 - when :num3,:number3 - 0x33 - when :num4,:number4 - 0x34 - when :num5,:number5 - 0x35 - when :num6,:number6 - 0x36 - when :num7,:number7 - 0x37 - when :num8,:number8 - 0x38 - when :num9,:number9 - 0x39 - #when - # 0x3A - #when - # 0x3B - #when - # 0x3C - #when - # 0x3D - #when - # 0x3E - #when - # 0x3F - #when - # 0x40 - when :a - 0x41 - when :b - 0x42 - when :c - 0x43 - when :d - 0x44 - when :e - 0x45 - when :f - 0x46 - when :g - 0x47 - when :h - 0x48 - when :i - 0x49 - when :j - 0x4A - when :k - 0x4B - when :l - 0x4C - when :m - 0x4D - when :n - 0x4E - when :o - 0x4F - when :p - 0x50 - when :q - 0x51 - when :r - 0x52 - when :s - 0x53 - when :t - 0x54 - when :u - 0x55 - when :v - 0x56 - when :w - 0x57 - when :x - 0x58 - when :y - 0x59 - when :z - 0x5A - when :win, :windows,:leftwin - 0x5B - when :rightwin - 0x5C - when :app,:application - 0x5D - #when - # 0x5E - when :sleep - 0x5F - when :numpad0,:numberpad0 - 0x60 - when :numpad1,:numberpad1 - 0x61 - when :numpad2,:numberpad2 - 0x62 - when :numpad3,:numberpad3 - 0x63 - when :numpad4,:numberpad4 - 0x64 - when :numpad5,:numberpad5 - 0x65 - when :numpad6,:numberpad6 - 0x66 - when :numpad7,:numberpad7 - 0x67 - when :numpad8,:numberpad8 - 0x68 - when :numpad9,:numberpad9 - 0x69 - when :multiply,:multiplication - 0x6A - when :add,:addition - 0x6B - when :separator - 0x6C - when :substract,:subtraction - 0x6D - when :decimal - 0x6E - when :divide,:division - 0x6F - when :f1 - 0x70 - when :f2 - 0x71 - when :f3 - 0x72 - when :f4 - 0x73 - when :f5 - 0x74 - when :f6 - 0x75 - when :f7 - 0x76 - when :f8 - 0x77 - when :f9 - 0x78 - when :f10 - 0x79 - when :f11 - 0x7A - when :f12 - 0x7B - when :f13 - 0x7C - when :f14 - 0x7D - when :f15 - 0x7E - when :f16 - 0x7F - when :f17 - 0x80 - when :f18 - 0x81 - when :f19 - 0x82 - when :f20 - 0x83 - when :f21 - 0x84 - when :f22 - 0x85 - when :f23 - 0x86 - when :f24 - 0x87 - #when - # 0x88 - #when - # 0x89 - #when - # 0x8A - #when - # 0x8B - #when - # 0x8C - #when - # 0x8D - #when - # 0x8E - #when - # 0x8F - when :numlock,:numberlock - 0x90 - when :scroll,:scrolllock - 0x91 - #when - # 0x92 - #when - # 0x93 - #when - # 0x94 - #when - # 0x95 - #when - # 0x96 - #when - # 0x97 - #when - # 0x98 - #when - # 0x99 - #when - # 0x9A - #when - # 0x9B - #when - # 0x9C - #when - # 0x9D - #when - # 0x9E - #when - # 0x9F - when :leftshift - 0xA0 - when :rightshift - 0xA1 - when :leftcontrol,:leftctrl - 0xA2 - when :rightcontrol,:rightctrl - 0xA3 - when :menu,:leftmenu - 0xA4 - when :rightmenu - 0xA5 - when :browserback - 0xA6 - when :browserforward - 0xA7 - when :browserrefresh - 0xA8 - when :browserstop - 0xA9 - when :browsersearch - 0xAA - when :browserfav,:browserfavourites - 0xAB - when :browserstart,:browserhome - 0xAC - when :mute,:volmute,:volumemute - 0xAD - when :voldown,:volumedown - 0xAE - when :volup,:volumeup - 0xAF - when :nexttrack - 0xB0 - when :previoustrack - 0xB1 - when :mediastop - 0xB2 - when :mediaplay,:mediapause - 0xB3 - when :mail - 0xB4 - when :mediaselect - 0xB5 - when :app1,:application1 - 0xB6 - when :app2,:application2 - 0xB7 - #when - # 0xB8 - #when - # 0xB9 - when :semicolon,:colon - 0xBA - when :equal, :plus - 0xBB - when :comma, :smallerthan - 0xBC - when :hyphen,:underscore,:understrike - 0xBD - when :period, :dot, :greaterthan - 0xBE - when :slash,:question,:questionmark,:forwardslash - 0xBF - when :grave, :graveaccent, :tilde,:leftquote - 0xC0 - #when - # 0xC1 - #when - # 0xC2 - #when - # 0xC3 - #when - # 0xC4 - #when - # 0xC5 - #when - # 0xC6 - #when - # 0xC7 - #when - # 0xC8 - #when - # 0xC9 - #when - # 0xCA - #when - # 0xCB - #when - # 0xCC - #when - # 0xCD - #when - # 0xCE - #when - # 0xCF - #when - # 0xD0 - #when - # 0xD1 - #when - # 0xD2 - #when - # 0xD3 - #when - # 0xD4 - #when - # 0xD5 - #when - # 0xD6 - #when - # 0xD7 - #when - # 0xD8 - #when - # 0xD9 - #when - # 0xDA - when :branket, :openbranket, :leftbranket, :opensquarebranket, :leftsquarebranket, :squarebranket, :curlybranket, :opencurlybranket, :leftcurlybranket - 0xDB - when :pipe, :pipes, :bar, :brokenbar, :backslash - 0xDC - when :closebranket, :closesquarebranket, :rightbranket, :rightsquarebranket, :closecurlybranket, :rightcurlybranket - 0xDD - when :quote,:singlequote,:doublequote, :rightquote, :acute, :acuteaccent - 0xDE - #when - # 0xDF - #when - # 0xE0 - #when - # 0xE1 - #when - # 0xE2 - #when - # 0xE3 - #when - # 0xE4 - #when - # 0xE5 - #when - # 0xE6 - #when - # 0xE7 - #when - # 0xE8 - #when - # 0xE9 - #when - # 0xEA - #when - # 0xEB - #when - # 0xEC - #when - # 0xED - #when - # 0xEE - #when - # 0xEF - #when - # 0xF0 - #when - # 0xF1 - #when - # 0xF2 - #when - # 0xF3 - #when - # 0xF4 - #when - # 0xF5 - #when - # 0xF6 - #when - # 0xF7 - #when - # 0xF8 - #when - # 0xF9 - when :play - 0xFA - when :zoom - 0xFB - #when - # 0xFC - #when - # 0xFD - #when - # 0xFE - #when - # 0xFF - else - 0 - end - end - - - + def self.code_from_name(name) + return name if name.is_a? Integer + if name.is_a? String + name = name.downcase.gsub(/[-_ ]/, '').to_sym + end + KEYNAMES_TO_CODES.fetch(name, 0) + end end diff --git a/sig/auto_click_methods.rbs b/sig/auto_click_methods.rbs new file mode 100644 index 0000000..acd74fc --- /dev/null +++ b/sig/auto_click_methods.rbs @@ -0,0 +1,61 @@ +module AutoClickMethods + def send_input: (Array[String]) -> void + + def get_screen_resolution: -> Array[Integer] + + def mouse_move: (Integer, Integer) -> void + + def mouse_move_percentage: (Integer, Integer) -> void + + def right_click: -> void + + def left_click: -> void + + def middle_click: -> void + + def mouse_down: (:right | :middle | :left) -> void + + def mouse_up: (:right | :middle | :left) -> void + + def double_click: -> void + + def cursor_position: -> Array[Integer] + + def mouse_scroll: (Integer) -> void + + def left_drag: (Integer, Integer, Integer, Integer) -> void + + def right_drag: (Integer, Integer, Integer, Integer) -> void + + def key_stroke: (*(:right | :middle | :left)) -> void + + def key_down: (:right | :middle | :left) -> void + + def key_up: (:right | :middle | :left) -> void + + def type: (String) -> void + + def get_key_state: (:right | :middle | :left) -> Integer +end + +module VirtualKey + def self.code_from_name: (Symbol | String | Integer) -> Integer +end + +module User32 + def self.GetCursorPos: (String) -> Integer + + def self.SetCursorPos: (Integer, Integer) -> Integer + + def self.SendInput: (Integer, String, Integer) -> Integer + + def self.GetKeyState: (Integer) -> Integer + + def self.GetSystemMetrics: (Integer) -> Integer +end + +module InputStructure + def self.mouse_input: (Integer, Integer, Integer, Integer) -> String + + def self.keyboard_input: (Integer, Integer) -> String +end diff --git a/virtual-key-codes.md b/virtual-key-codes.md new file mode 100644 index 0000000..60e3177 --- /dev/null +++ b/virtual-key-codes.md @@ -0,0 +1,197 @@ +# Virtual-Key Codes + +The following table shows the symbolic constant names, hexadecimal values, and mouse or keyboard equivalents for the +virtual-key codes used by the system. The codes are listed in numeric order. + +| Constant | Value | Description | +|--------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `VK_LBUTTON` | 0x01 | Left mouse button | +| `VK_RBUTTON` | 0x02 | Right mouse button | +| `VK_CANCEL` | 0x03 | Control-break processing | +| `VK_MBUTTON` | 0x04 | Middle mouse button | +| `VK_XBUTTON1` | 0x05 | X1 mouse button | +| `VK_XBUTTON2` | 0x06 | X2 mouse button | +| `-` | 0x07 | Reserved | +| `VK_BACK` | 0x08 | BACKSPACE key | +| `VK_TAB` | 0x09 | TAB key | +| `-` | 0x0A-0B | Reserved | +| `VK_CLEAR` | 0x0C | CLEAR key | +| `VK_RETURN` | 0x0D | ENTER key | +| `-` | 0x0E-0F | Unassigned | +| `VK_SHIFT` | 0x10 | SHIFT key | +| `VK_CONTROL` | 0x11 | CTRL key | +| `VK_MENU` | 0x12 | ALT key | +| `VK_PAUSE` | 0x13 | PAUSE key | +| `VK_CAPITAL` | 0x14 | CAPS LOCK key | +| `VK_KANA` | 0x15 | IME Kana mode | +| `VK_HANGUL` | 0x15 | IME Hangul mode | +| `VK_IME_ON` | 0x16 | IME On | +| `VK_JUNJA` | 0x17 | IME Junja mode | +| `VK_FINAL` | 0x18 | IME final mode | +| `VK_HANJA` | 0x19 | IME Hanja mode | +| `VK_KANJI` | 0x19 | IME Kanji mode | +| `VK_IME_OFF` | 0x1A | IME Off | +| `VK_ESCAPE` | 0x1B | ESC key | +| `VK_CONVERT` | 0x1C | IME convert | +| `VK_NONCONVERT` | 0x1D | IME nonconvert | +| `VK_ACCEPT` | 0x1E | IME accept | +| `VK_MODECHANGE` | 0x1F | IME mode change request | +| `VK_SPACE` | 0x20 | SPACEBAR | +| `VK_PRIOR` | 0x21 | PAGE UP key | +| `VK_NEXT` | 0x22 | PAGE DOWN key | +| `VK_END` | 0x23 | END key | +| `VK_HOME` | 0x24 | HOME key | +| `VK_LEFT` | 0x25 | LEFT ARROW key | +| `VK_UP` | 0x26 | UP ARROW key | +| `VK_RIGHT` | 0x27 | RIGHT ARROW key | +| `VK_DOWN` | 0x28 | DOWN ARROW key | +| `VK_SELECT` | 0x29 | SELECT key | +| `VK_PRINT` | 0x2A | PRINT key | +| `VK_EXECUTE` | 0x2B | EXECUTE key | +| `VK_SNAPSHOT` | 0x2C | PRINT SCREEN key | +| `VK_INSERT` | 0x2D | INS key | +| `VK_DELETE` | 0x2E | DEL key | +| `VK_HELP` | 0x2F | HELP key | +| | 0x30 | 0 key | +| | 0x31 | 1 key | +| | 0x32 | 2 key | +| | 0x33 | 3 key | +| | 0x34 | 4 key | +| | 0x35 | 5 key | +| | 0x36 | 6 key | +| | 0x37 | 7 key | +| | 0x38 | 8 key | +| | 0x39 | 9 key | +| `-` | 0x3A-40 | Undefined | +| | 0x41 | A key | +| | 0x42 | B key | +| | 0x43 | C key | +| | 0x44 | D key | +| | 0x45 | E key | +| | 0x46 | F key | +| | 0x47 | G key | +| | 0x48 | H key | +| | 0x49 | I key | +| | 0x4A | J key | +| | 0x4B | K key | +| | 0x4C | L key | +| | 0x4D | M key | +| | 0x4E | N key | +| | 0x4F | O key | +| | 0x50 | P key | +| | 0x51 | Q key | +| | 0x52 | R key | +| | 0x53 | S key | +| | 0x54 | T key | +| | 0x55 | U key | +| | 0x56 | V key | +| | 0x57 | W key | +| | 0x58 | X key | +| | 0x59 | Y key | +| | 0x5A | Z key | +| `VK_LWIN` | 0x5B | Left Windows key | +| `VK_RWIN` | 0x5C | Right Windows key | +| `VK_APPS` | 0x5D | Applications key | +| `-` | 0x5E | Reserved | +| `VK_SLEEP` | 0x5F | Computer Sleep key | +| `VK_NUMPAD0` | 0x60 | Numeric keypad 0 key | +| `VK_NUMPAD1` | 0x61 | Numeric keypad 1 key | +| `VK_NUMPAD2` | 0x62 | Numeric keypad 2 key | +| `VK_NUMPAD3` | 0x63 | Numeric keypad 3 key | +| `VK_NUMPAD4` | 0x64 | Numeric keypad 4 key | +| `VK_NUMPAD5` | 0x65 | Numeric keypad 5 key | +| `VK_NUMPAD6` | 0x66 | Numeric keypad 6 key | +| `VK_NUMPAD7` | 0x67 | Numeric keypad 7 key | +| `VK_NUMPAD8` | 0x68 | Numeric keypad 8 key | +| `VK_NUMPAD9` | 0x69 | Numeric keypad 9 key | +| `VK_MULTIPLY` | 0x6A | Multiply key | +| `VK_ADD` | 0x6B | Add key | +| `VK_SEPARATOR` | 0x6C | Separator key | +| `VK_SUBTRACT` | 0x6D | Subtract key | +| `VK_DECIMAL` | 0x6E | Decimal key | +| `VK_DIVIDE` | 0x6F | Divide key | +| `VK_F1` | 0x70 | F1 key | +| `VK_F2` | 0x71 | F2 key | +| `VK_F3` | 0x72 | F3 key | +| `VK_F4` | 0x73 | F4 key | +| `VK_F5` | 0x74 | F5 key | +| `VK_F6` | 0x75 | F6 key | +| `VK_F7` | 0x76 | F7 key | +| `VK_F8` | 0x77 | F8 key | +| `VK_F9` | 0x78 | F9 key | +| `VK_F10` | 0x79 | F10 key | +| `VK_F11` | 0x7A | F11 key | +| `VK_F12` | 0x7B | F12 key | +| `VK_F13` | 0x7C | F13 key | +| `VK_F14` | 0x7D | F14 key | +| `VK_F15` | 0x7E | F15 key | +| `VK_F16` | 0x7F | F16 key | +| `VK_F17` | 0x80 | F17 key | +| `VK_F18` | 0x81 | F18 key | +| `VK_F19` | 0x82 | F19 key | +| `VK_F20` | 0x83 | F20 key | +| `VK_F21` | 0x84 | F21 key | +| `VK_F22` | 0x85 | F22 key | +| `VK_F23` | 0x86 | F23 key | +| `VK_F24` | 0x87 | F24 key | +| `-` | 0x88-8F | Reserved | +| `VK_NUMLOCK` | 0x90 | NUM LOCK key | +| `VK_SCROLL` | 0x91 | SCROLL LOCK key | +| `-` | 0x92-96 | OEM specific | +| `-` | 0x97-9F | Unassigned | +| `VK_LSHIFT` | 0xA0 | Left SHIFT key | +| `VK_RSHIFT` | 0xA1 | Right SHIFT key | +| `VK_LCONTROL` | 0xA2 | Left CONTROL key | +| `VK_RCONTROL` | 0xA3 | Right CONTROL key | +| `VK_LMENU` | 0xA4 | Left ALT key | +| `VK_RMENU` | 0xA5 | Right ALT key | +| `VK_BROWSER_BACK` | 0xA6 | Browser Back key | +| `VK_BROWSER_FORWARD` | 0xA7 | Browser Forward key | +| `VK_BROWSER_REFRESH` | 0xA8 | Browser Refresh key | +| `VK_BROWSER_STOP` | 0xA9 | Browser Stop key | +| `VK_BROWSER_SEARCH` | 0xAA | Browser Search key | +| `VK_BROWSER_FAVORITES` | 0xAB | Browser Favorites key | +| `VK_BROWSER_HOME` | 0xAC | Browser Start and Home key | +| `VK_VOLUME_MUTE` | 0xAD | Volume Mute key | +| `VK_VOLUME_DOWN` | 0xAE | Volume Down key | +| `VK_VOLUME_UP` | 0xAF | Volume Up key | +| `VK_MEDIA_NEXT_TRACK` | 0xB0 | Next Track key | +| `VK_MEDIA_PREV_TRACK` | 0xB1 | Previous Track key | +| `VK_MEDIA_STOP` | 0xB2 | Stop Media key | +| `VK_MEDIA_PLAY_PAUSE` | 0xB3 | Play/Pause Media key | +| `VK_LAUNCH_MAIL` | 0xB4 | Start Mail key | +| `VK_LAUNCH_MEDIA_SELECT` | 0xB5 | Select Media key | +| `VK_LAUNCH_APP1` | 0xB6 | Start Application 1 key | +| `VK_LAUNCH_APP2` | 0xB7 | Start Application 2 key | +| `-` | 0xB8-B9 | Reserved | +| `VK_OEM_1` | 0xBA | Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the `;:` key | +| `VK_OEM_PLUS` | 0xBB | For any country/region, the `+` key | +| `VK_OEM_COMMA` | 0xBC | For any country/region, the `,` key | +| `VK_OEM_MINUS` | 0xBD | For any country/region, the `-` key | +| `VK_OEM_PERIOD` | 0xBE | For any country/region, the `.` key | +| `VK_OEM_2` | 0xBF | Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the `/?` key | +| `VK_OEM_3` | 0xC0 | Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the `` `~ `` key | +| `-` | 0xC1-DA | Reserved | +| `VK_OEM_4` | 0xDB | Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the `[{` key | +| `VK_OEM_5` | 0xDC | Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the `\\|` key | +| `VK_OEM_6` | 0xDD | Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the `]}` key | +| `VK_OEM_7` | 0xDE | Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the `'"` key | +| `VK_OEM_8` | 0xDF | Used for miscellaneous characters; it can vary by keyboard. | +| `-` | 0xE0 | Reserved | +| `-` | 0xE1 | OEM specific | +| `VK_OEM_102` | 0xE2 | The `<>` keys on the US standard keyboard, or the `\\|` key on the non-US 102-key keyboard | +| `-` | 0xE3-E4 | OEM specific | +| `VK_PROCESSKEY` | 0xE5 | IME PROCESS key | +| `-` | 0xE6 | OEM specific | +| `VK_PACKET` | 0xE7 | Used to pass Unicode characters as if they were keystrokes. The `VK_PACKET` key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in [`KEYBDINPUT`](/windows/win32/api/winuser/ns-winuser-keybdinput), [`SendInput`](/windows/win32/api/winuser/nf-winuser-sendinput), [`WM_KEYDOWN`](wm-keydown.md), and [`WM_KEYUP`](wm-keyup.md) | +| `-` | 0xE8 | Unassigned | +| `-` | 0xE9-F5 | OEM specific | +| `VK_ATTN` | 0xF6 | Attn key | +| `VK_CRSEL` | 0xF7 | CrSel key | +| `VK_EXSEL` | 0xF8 | ExSel key | +| `VK_EREOF` | 0xF9 | Erase EOF key | +| `VK_PLAY` | 0xFA | Play key | +| `VK_ZOOM` | 0xFB | Zoom key | +| `VK_NONAME` | 0xFC | Reserved | +| `VK_PA1` | 0xFD | PA1 key | +| `VK_OEM_CLEAR` | 0xFE | Clear key |