#============================================================================== # # GaryCXJk - InpEx v1.02 # * Last Updated: 2014.04.04 # * Level: Medium # * Requires: N/A # #============================================================================== $imported = {} if $imported.nil? $imported["CXJ-InpEx"] = true #============================================================================== # # Changelog: # #------------------------------------------------------------------------------ # 2014.04.04 - v1.02 # # * Added: Ability to disable keys temporarily when InputEx is bound to Input # * Added: Ability to disable directions temporarily when InputEx is bound to # Input # #------------------------------------------------------------------------------ # 2013.08.19 - v1.01 # # * Added: Basic mouse control on menus # * Added: Message commands to display key presses # #------------------------------------------------------------------------------ # 2013.07.31 - v1.00 # # * Initial release # #============================================================================== # # Sometimes you need extra ways to control the game, and sometimes the amount # of available buttons and keys isn't enough for the game. Or, you don't want # people, especially non-RPG Maker users, to rely on F1 to change the gamepad # and / or keyboard settings. # # This script adds a way to bind new keys both during development as well as # in-game. # #============================================================================== # # Installation: # # Make sure to put this below Materials, but above Main Process. # # This script adds aliases for several methods. If you are sure no method that # is used by other scripts get overridden, you can place it anywhere, # otherwise, make sure this script is loaded after any other script overriding # these methods, otherwise this script stops working. # #------------------------------------------------------------------------------ # Aliased methods: # # * module Input (if keyboard or gamepad hooks are enabled) # - update # - press?(key) # - repeat?(key) # - trigger?(key) # - dir4 # - dir8 # * module SceneManager # - snapshot_for_background # * class Window_Base # - convert_escape_characters(text) # - process_escape_character(code, text, pos) # * class Window_Selectable (if mouse hooks are enabled) # - update # #============================================================================== # # Usage: # # Before I'll start, this guide assumes you have set INCLUDE_CORE to true. # If that isn't the case, the modules are included in CXJ::INPEX. For example # the Mouse module can be found as CXJ::INPEX::Mouse. # # In essence, the script is plug-and-play, it already works once installed. # However, if you want to add more keybindings, you can always do that. You # can later call that bound key in your own script using the same symbol. # # In order to bind keys and buttons in-game, you can use the following methods: # # Keyboard.bind_keyboard(sym, key) # Gamepad.bind_gamepad(sym, key) # # You can also unbind keys: # # Keyboard.unbind_keyboard(sym, key) # Gamepad.unbind_gamepad(sym, key) # # Most other methods in these modules correspond to the Input equivalent, so # those don't need explaining. # # To check whether a key or button is pressed for keybinding, you can iterate # over each key. However, as gamepads have a variable amount of buttons, a # method has been defined to determine the amount of buttons. # # Gamepad.get_button_range # # If you want certain key binds or directions to temporarily be disabled, you # can use the following method: # # Input.set_key_enabled(sym, status) # Input.set_dir_enabled(dir, status) # # The symbol refers to the kind of button you want to disable, and correspond # to the keys defined in DEFAULT_BIND in the script settings. With directions, # it always assumes eight directions, meaning, if you want to disable all left # movements, even diagonal, you should disable the diagonal directions as # well. # # You can also use mouse control. It covers most of the basic menu control, # but if you need additional functionality, you can always use the following # methods: # # Mouse.x # Mouse.y # Mouse.left_press? # Mouse.left_trigger? # Mouse.right_press? # Mouse.right_trigger? # Mouse.middle_press? # Mouse.middle_trigger? # # There is functionality for custom mouse pointers set. You first need to # specify a bitmap image that serves as a pointer, the origin of the pointer # and the width and height, and you're set. You can even do it in script. # # Mouse.bitmap = bitmap # Mouse.ox = origin_x # Mouse.oy = origin_y # Mouse.width = width # Mouse.height = height # # You can also specify the pattern, as in, which mouse pointer to use in the # same image file. # # Mouse.pattern = pattern # # You can easily animate the mouse by putting multiple frames of the mouse # pointer next to each other, each frame having the same size as specified # on the mouse. Do note that blank frames will still be used in the animation, # so be sure to pad single-frame pointers, or use separate images for animated # mouse pointers. # # To display keyboard buttons during messages, for example, to show certain # keybinds, use the following tags: # # \key[code] - Textual representation of one key # \keyi[code] - Picture representation of one key # \bkey[code] - Textual representation of bound keys # \bkeyi[code] - Picture representation of bound keys # # There's a simple window that serves as an example for key presses, and can # actually be used to poll for keyboard presses. To use it, you'll need to # make a Window_SimpleKeyTest instance. # # Window_SimpleKeyTest.new(array_variable, option1, option2...) # # array_variable is an array, preferably empty. When the window closes after # a button has pressed, it will store the key code inside this array. # # You can also pass on symbols that determine what gets ignored. # # :no_lr - Ignores the left and right variants of shift, ctrl and alt. # :only_lr - Ignores the directionless shift, ctrl and alt. # :no_mouse - Ignores mouse presses. # # An example code: # # varr = [] # wnd = Window_SimpleKeyTest.new(varr, :only_lr) # unless wnd.close? # wnd.update # Fiber.yield # end # p varr # #============================================================================== # # License: # # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE # Version 2, December 2004 # # Copyright (C) 2013 Sam Hocevar # # Everyone is permitted to copy and distribute verbatim or modified # copies of this license document, and changing it is allowed as long # as the name is changed. # # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION # # 0. You just DO WHAT THE FUCK YOU WANT TO. # # See http://www.wtfpl.net/ for more details. # #------------------------------------------------------------------------------ # Extra notes: # # This license was picked due to the fact that in my opinion this script # shouldn't be restricted by the creative commons license, which mostly still # requires you to attribute the content to the original creator. I also feel # like this script could help others understand certain mechanics and can # learn from it without the fear of violating a license due to similar coding. # # You can still give credits if you want though, and are free to pick the # following names when you give credit: # # * GaryCXJk # * Gary A.M. Kertopermono # * G.A.M. Kertopermono # * GARYCXJK # # To make it clear, this license allows you to DO WHAT THE FUCK YOU WANT TO, # which means you can use it in commercial as well as non-commercial products, # you can modify it, redistribute it, make toilet paper out of it, sell it on # eBay and win a presidential election with it. But it's mostly for making # games. There are no restrictions, no need to attribute regardless of the # amount of modifications made, you are allowed to remove all references to me, # you are allowed to change the license, although that's pretty much a dick # move (actually, I'm not sure if you can change the license or not, but let's # just not be dicks here, mmm'kay?), you are allowed to directly sell this # script or monetize on it on your own site. # # This script was originally hosted on: # http://area91.multiverseworks.com # #============================================================================== # # The code below defines the settings of this script, and are there to be # modified. # #============================================================================== module CXJ module INPEX #------------------------------------------------------------------------ # General settings #------------------------------------------------------------------------ INCLUDE_CORE = true # Include core to root #------------------------------------------------------------------------ # Hook settings #------------------------------------------------------------------------ ENABLE_COMPATIBILITY = false # Enable to fall back to vanilla controls HOOK_KEYBOARD_TO_INPUT = true HOOK_GAMEPAD_TO_INPUT = true #------------------------------------------------------------------------ # Keyboard settings #------------------------------------------------------------------------ DISABLE_F12_RESET = true # Might not be entirely reliable KEYBOARD_ICONS = "Graphics/System/KeyboardIcon" DEFAULT_ICON_HEIGHT = 24 CUSTOM_KEY_ICON = {} CUSTOM_KEY_ICON[:K_BACKSPACE] = [ 0, 384, 40, 24] CUSTOM_KEY_ICON[:K_TAB] = [ 40, 384, 40, 24] CUSTOM_KEY_ICON[:K_ENTER] = [ 80, 384, 40, 24] CUSTOM_KEY_ICON[:K_SHIFT] = [120, 384, 40, 24] CUSTOM_KEY_ICON[:K_CTRL] = [160, 384, 40, 24] CUSTOM_KEY_ICON[:K_CAPSLOCK] = [200, 384, 40, 24] CUSTOM_KEY_ICON[:K_SPACE] = [240, 384, 48, 24] CUSTOM_KEY_ICON["/"] = [ 0, 408, 24, 24] CUSTOM_KEY_ICON["\\"] = [ 24, 408, 24, 24] CUSTOM_KEY_ICON["["] = [ 48, 408, 24, 24] CUSTOM_KEY_ICON["]"] = [ 72, 408, 24, 24] CUSTOM_KEY_ICON[";"] = [ 96, 408, 24, 24] CUSTOM_KEY_ICON["'"] = [120, 408, 24, 24] CUSTOM_KEY_ICON["`"] = [144, 408, 24, 24] #CUSTOM_KEY_ICON["+"] = [168, 408, 24, 24] #CUSTOM_KEY_ICON["-"] = [192, 408, 24, 24] #CUSTOM_KEY_ICON["*"] = [216, 408, 24, 24] CUSTOM_KEY_ICON["="] = [240, 408, 24, 24] #------------------------------------------------------------------------ # Gamepad settings #------------------------------------------------------------------------ DEFAULT_GAMEPAD_TYPE = :xinput DEFAULT_GAMEPAD_NUM = 0 #------------------------------------------------------------------------ # Mouse settings #------------------------------------------------------------------------ ENABLE_CUSTOM_POINTER = true HIDE_MOUSE_POINTER = true HOOK_MOUSE_TO_WINDOWS = true DEFAULT_MOUSE_BITMAP = "Graphics/System/Pointer" DEFAULT_MOUSE_ORIGIN = [16, 16] DEFAULT_MOUSE_SIZE = [32, 32] DEFAULT_MOUSE_PATTERN = 0 DEFAULT_MOUSE_TICKS_PER_FRAME = 5 #------------------------------------------------------------------------ # Game message vocabulary #------------------------------------------------------------------------ VOCAB_UNDEFINED = "UNDEFINED" VOCAB_KEY_UNKNOWN = "KEY" VOCAB_AND = "and" VOCAB_OR = "or" #------------------------------------------------------------------------ # The default bind settings for keyboard. #------------------------------------------------------------------------ DEFAULT_BIND = { :UP => [:K_UP, :K_NUMPAD8], :DOWN => [:K_DOWN, :K_NUMPAD2], :LEFT => [:K_LEFT, :K_NUMPAD4], :RIGHT => [:K_RIGHT, :K_NUMPAD6], :A => [:K_SHIFT], :B => [:K_ESC, :K_NUMPAD0, :K_X], :C => [:K_SPACE, :K_ENTER, :K_Z], :X => [:K_A], :Y => [:K_S], :Z => [:K_D], :L => [:K_Q], :R => [:K_W], :SHIFT => [:K_SHIFT, :K_LSHIFT, :K_RSHIFT], :CTRL => [:K_CTRL, :K_LCTRL, :K_RCTRL], :ALT => [:K_ALT, :K_LALT, :K_RALT], :F5 => [:K_F5], :F6 => [:K_F6], :F7 => [:K_F7], :F8 => [:K_F8], :F9 => [:K_F9], :TAB => [:K_TAB], :SLOT1 => [:K_1], :SLOT2 => [:K_2], :SLOT3 => [:K_3], :SLOT4 => [:K_4], :SLOT5 => [:K_5], } #------------------------------------------------------------------------ # The default bind settings for gamepad. #------------------------------------------------------------------------ DEFAULT_BIND_GAMEPAD = { :UP => [:X_STHUMBL_UP], :DOWN => [:X_STHUMBL_DOWN], :LEFT => [:X_STHUMBL_LEFT], :RIGHT => [:X_STHUMBL_RIGHT], :A => [:X_A], :B => [:X_B], :C => [:X_X], :X => [:X_Y], :Y => [:X_LSHOULDER], :Z => [:X_RSHOULDER], :L => [:X_BACK], :R => [:X_START], } end end #============================================================================== # # The code below should not be altered unless you know what you're doing. # #============================================================================== #---------------------------------------------------------------------------- # * Detects The OS Running # So far only Windows is supported, but it's being prepared for the # possibility of other operating systems. #---------------------------------------------------------------------------- def get_os case RUBY_PLATFORM when /win32/i :win32 else :unknown end end module CXJ module INPEX #------------------------------------------------------------------------ # This block defines the functions to use. #------------------------------------------------------------------------ if get_os == :win32 module WIN32 GETACTIVEWINDOW = Win32API.new("user32", "GetActiveWindow", '', 'L') GETASYNCKEYSTATE = Win32API.new("user32", "GetAsyncKeyState", 'L', 'L') GETCURSORPOS = Win32API.new("user32", "GetCursorPos", 'P', 'V') SCREENTOCLIENT = Win32API.new("user32", "ScreenToClient", 'LP', 'V') SHOWCURSOR = Win32API.new("user32", "ShowCursor", 'L', 'L') MAPVIRTUALKEY = Win32API.new("user32", "MapVirtualKey", 'II', 'I') GETKEYBOARDSTATE = Win32API.new("user32", "GetKeyboardState", 'P', 'V') TOUNICODE = Win32API.new("user32", "ToUnicode", 'LLPPIL', 'I') end end module UNKNOWN GETACIVEWINDOW = Proc.new {} GETASYNCKEYSTATE = Proc.new {} GETCURSORPOS = Proc.new {} SCREENTOCLIENT = Proc.new {} SHOWCURSOR = Proc.new {} MAPVIRTUALKEY = Proc.new {} GETKEYBOARDSTATE = Proc.new {} TOUNICODE = Proc.new {} end module CORE #======================================================================== # ** Keys #------------------------------------------------------------------------ # The key codes that correspond to keys. #======================================================================== module Keys M_LEFT = 0x01 M_RIGHT = 0x02 M_MIDDLE = 0x04 K_BACKSPACE = 0x08 K_TAB = 0x09 K_ENTER = 0x0D K_RETURN = 0x0D K_SHIFT = 0x10 K_CTRL = 0x11 K_ALT = 0x12 K_MENU = 0x12 K_PAUSE = 0x13 K_CAPSLOCK = 0x14 K_ESCAPE = 0x1B K_ESC = 0x1B K_SPACE = 0x20 K_PGUP = 0x21 K_PGDOWN = 0x22 K_END = 0x23 K_HOME = 0x24 K_LEFT = 0x25 K_UP = 0x26 K_RIGHT = 0x27 K_DOWN = 0x28 K_PRINTSCREEN = 0x2C K_INSERT = 0x2D K_DELETE = 0x2E K_0 = 0x30 K_1 = 0x31 K_2 = 0x32 K_3 = 0x33 K_4 = 0x34 K_5 = 0x35 K_6 = 0x36 K_7 = 0x37 K_8 = 0x38 K_9 = 0x39 K_A = 0x41 K_B = 0x42 K_C = 0x43 K_D = 0x44 K_E = 0x45 K_F = 0x46 K_G = 0x47 K_H = 0x48 K_I = 0x49 K_J = 0x4A K_K = 0x4B K_L = 0x4C K_M = 0x4D K_N = 0x4E K_O = 0x4F K_P = 0x50 K_Q = 0x51 K_R = 0x52 K_S = 0x53 K_T = 0x54 K_U = 0x55 K_V = 0x56 K_W = 0x57 K_X = 0x58 K_Y = 0x59 K_Z = 0x5A K_LWIN = 0x5B K_RWIN = 0x5C K_NUMPAD0 = 0x60 K_NUMPAD1 = 0x61 K_NUMPAD2 = 0x62 K_NUMPAD3 = 0x63 K_NUMPAD4 = 0x64 K_NUMPAD5 = 0x65 K_NUMPAD6 = 0x66 K_NUMPAD7 = 0x67 K_NUMPAD8 = 0x68 K_NUMPAD9 = 0x69 K_MULTIPLY = 0x6A K_ADD = 0x6B K_SEPARATOR = 0x6C K_SUBTRACT = 0x6D K_DECIMAL = 0x6E K_DIVIDE = 0x6F K_F1 = 0x70 K_F2 = 0x71 K_F3 = 0x72 K_F4 = 0x73 K_F5 = 0x74 K_F6 = 0x75 K_F7 = 0x76 K_F8 = 0x77 K_F9 = 0x78 K_F10 = 0x79 K_F11 = 0x7A K_F12 = 0x7B K_NUMLOCK = 0x90 K_SCROLLOCK = 0x91 K_LSHIFT = 0xA0 K_RSHIFT = 0xA1 K_LCTRL = 0xA2 K_RCTRL = 0xA3 K_LALT = 0xA4 K_LMENU = 0xA4 K_RALT = 0xA5 K_RMENU = 0xA5 K_OEM_1 = 0xBA K_OEM_PLUS = 0xBB K_OEM_COMMA = 0xBC K_OEM_MINUS = 0xBD K_OEM_PERIOD = 0xBE K_OEM_2 = 0xBF K_OEM_3 = 0xC0 K_OEM_4 = 0xDB K_OEM_5 = 0xDC K_OEM_6 = 0xDD K_OEM_7 = 0xDE K_OEM_8 = 0xDF KEY_STRING = [] KEY_STRING[M_LEFT] = "Left Mouse Button" KEY_STRING[M_RIGHT] = "Right Mouse Button" KEY_STRING[M_MIDDLE] = "Middle Mouse Button" KEY_STRING[K_BACKSPACE] = "Backspace" KEY_STRING[K_TAB] = "Tab" KEY_STRING[K_ENTER] = "Enter" KEY_STRING[K_SHIFT] = "Shift" KEY_STRING[K_CTRL] = "Ctrl" KEY_STRING[K_MENU] = "Alt" KEY_STRING[K_PAUSE] = "Pause" KEY_STRING[K_CAPSLOCK] = "Caps Lock" KEY_STRING[K_ESCAPE] = "Escape" KEY_STRING[K_SPACE] = "Space" KEY_STRING[K_PGUP] = "Page Up" KEY_STRING[K_PGDOWN] = "Page Down" KEY_STRING[K_END] = "End" KEY_STRING[K_HOME] = "Home" KEY_STRING[K_LEFT] = "Left" KEY_STRING[K_UP] = "Up" KEY_STRING[K_RIGHT] = "Right" KEY_STRING[K_DOWN] = "Down" KEY_STRING[K_PRINTSCREEN] = "Print Screen" KEY_STRING[K_INSERT] = "Insert" KEY_STRING[K_DELETE] = "Delete" KEY_STRING[K_0] = "0" KEY_STRING[K_1] = "1" KEY_STRING[K_2] = "2" KEY_STRING[K_3] = "3" KEY_STRING[K_4] = "4" KEY_STRING[K_5] = "5" KEY_STRING[K_6] = "6" KEY_STRING[K_7] = "7" KEY_STRING[K_8] = "8" KEY_STRING[K_9] = "9" KEY_STRING[K_A] = "A" KEY_STRING[K_B] = "B" KEY_STRING[K_C] = "C" KEY_STRING[K_D] = "D" KEY_STRING[K_E] = "E" KEY_STRING[K_F] = "F" KEY_STRING[K_G] = "G" KEY_STRING[K_H] = "H" KEY_STRING[K_I] = "I" KEY_STRING[K_J] = "J" KEY_STRING[K_K] = "K" KEY_STRING[K_L] = "L" KEY_STRING[K_M] = "M" KEY_STRING[K_N] = "N" KEY_STRING[K_O] = "O" KEY_STRING[K_P] = "P" KEY_STRING[K_Q] = "Q" KEY_STRING[K_R] = "R" KEY_STRING[K_S] = "S" KEY_STRING[K_T] = "T" KEY_STRING[K_U] = "U" KEY_STRING[K_V] = "V" KEY_STRING[K_W] = "W" KEY_STRING[K_X] = "X" KEY_STRING[K_Y] = "Y" KEY_STRING[K_Z] = "Z" KEY_STRING[K_MULTIPLY] = "Numpad *" KEY_STRING[K_ADD] = "Numpad +" KEY_STRING[K_SUBTRACT] = "Numpad -" KEY_STRING[K_DECIMAL] = "Numpad ." KEY_STRING[K_DIVIDE] = "Numpad /" KEY_STRING[K_NUMPAD0] = "Numpad 0" KEY_STRING[K_NUMPAD1] = "Numpad 1" KEY_STRING[K_NUMPAD2] = "Numpad 2" KEY_STRING[K_NUMPAD3] = "Numpad 3" KEY_STRING[K_NUMPAD4] = "Numpad 4" KEY_STRING[K_NUMPAD5] = "Numpad 5" KEY_STRING[K_NUMPAD6] = "Numpad 6" KEY_STRING[K_NUMPAD7] = "Numpad 7" KEY_STRING[K_NUMPAD8] = "Numpad 8" KEY_STRING[K_NUMPAD9] = "Numpad 9" KEY_STRING[K_F1] = "F1" KEY_STRING[K_F2] = "F2" KEY_STRING[K_F3] = "F3" KEY_STRING[K_F4] = "F4" KEY_STRING[K_F5] = "F5" KEY_STRING[K_F6] = "F6" KEY_STRING[K_F7] = "F7" KEY_STRING[K_F8] = "F8" KEY_STRING[K_F9] = "F9" KEY_STRING[K_F10] = "F10" KEY_STRING[K_F11] = "F11" KEY_STRING[K_F12] = "F12" #KEY_STRING[K_OEM_PLUS] = "+" KEY_STRING[K_OEM_COMMA] = "," KEY_STRING[K_OEM_MINUS] = "-" KEY_STRING[K_OEM_PERIOD] = "." if get_os != :unknown op = nil case get_os when :win32 op = CXJ::INPEX::WIN32 end unless op.nil? 256.times do |i| next unless KEY_STRING[i].nil? || KEY_STRING[i].empty? chr = op::MAPVIRTUALKEY.call(i, 2) next if chr == 0 KEY_STRING[i] = [chr].pack("C") end end end end #======================================================================== # ** Mouse #------------------------------------------------------------------------ # The mouse. #======================================================================== module Mouse @@mouse_viewport = nil @@mouse_pointer = nil @@ox = 0 @@oy = 0 @@frame = 0 @@pattern = 0 @@ticks_per_frame = 0 @@tick = 0 case get_os when :win32 include CXJ::INPEX::WIN32 else include CXJ::INPEX::UNKNOWN end #-------------------------------------------------------------------- # * New: Update Frame (Mouse) #-------------------------------------------------------------------- def self.update init_pointer if(CXJ::INPEX::HIDE_MOUSE_POINTER) mouse_x = Mouse.x mouse_y = Mouse.y if Mouse.in_screen? Mouse.show_cursor(false) else Mouse.show_cursor(true) end end @@mouse_pointer.x = 0 + @@ox @@mouse_pointer.y = 0 + @@oy @@mouse_pointer.ox = @@ox + width * frame @@mouse_pointer.oy = @@oy + height * pattern @@mouse_viewport.rect.x = Mouse.x - @@ox @@mouse_viewport.rect.y = Mouse.y - @@oy @@tick+=1 if(@@tick == @@ticks_per_frame) @@tick = 0 @@frame = (@@frame + 1) % (bitmap.width / width) if !bitmap.nil? && bitmap.width >= width end end #-------------------------------------------------------------------- # * New: Initialize Mouse Pointer #-------------------------------------------------------------------- def self.init_pointer if @@mouse_viewport.nil? @@mouse_viewport = Viewport.new(0, 0, CXJ::INPEX::DEFAULT_MOUSE_SIZE[0], CXJ::INPEX::DEFAULT_MOUSE_SIZE[1]) @@mouse_viewport.z = 300 end if @@mouse_pointer.nil? @@mouse_pointer = Sprite.new(@@mouse_viewport) @@mouse_pointer.z = 200 @@mouse_pointer.bitmap = Bitmap.new(32, 32) if CXJ::INPEX::DEFAULT_MOUSE_BITMAP.nil? || CXJ::INPEX::DEFAULT_MOUSE_BITMAP.empty? @@mouse_pointer.bitmap = Cache.normal_bitmap(CXJ::INPEX::DEFAULT_MOUSE_BITMAP) unless CXJ::INPEX::DEFAULT_MOUSE_BITMAP.nil? || CXJ::INPEX::DEFAULT_MOUSE_BITMAP.empty? @@ox = CXJ::INPEX::DEFAULT_MOUSE_ORIGIN[0] @@oy = CXJ::INPEX::DEFAULT_MOUSE_ORIGIN[0] @@frame = 0 @@pattern = CXJ::INPEX::DEFAULT_MOUSE_PATTERN @@ticks_per_frame = CXJ::INPEX::DEFAULT_MOUSE_TICKS_PER_FRAME @@tick = 0 end end #-------------------------------------------------------------------- # * New: Assign Pointer Bitmap #-------------------------------------------------------------------- def self.bitmap=(bitmap) init_pointer @@mouse_pointer.bitmap = bitmap @@ox = 0 @@oy = 0 @@frame = 0 @@pattern = 0 end #-------------------------------------------------------------------- # * New: Pointer Bitmap #-------------------------------------------------------------------- def self.bitmap @@mouse_pointer.bitmap end #-------------------------------------------------------------------- # * New: Set Pointer x-origin #-------------------------------------------------------------------- def self.ox=(ox) @@ox = ox end #-------------------------------------------------------------------- # * New: Set Pointer y-origin #-------------------------------------------------------------------- def self.oy=(oy) @@oy = oy end #-------------------------------------------------------------------- # * New: Pointer x-origin #-------------------------------------------------------------------- def self.ox @@ox end #-------------------------------------------------------------------- # * New: Pointer y-origin #-------------------------------------------------------------------- def self.oy @@oy end #-------------------------------------------------------------------- # * New: Set z-coordinate #-------------------------------------------------------------------- def self.z=(z) @@mouse_viewport.z = z end #-------------------------------------------------------------------- # * New: z-coordinate #-------------------------------------------------------------------- def self.z @@mouse_viewport.z end #-------------------------------------------------------------------- # * New: Set Frame #-------------------------------------------------------------------- def self.frame=(frame) @@frame = frame end #-------------------------------------------------------------------- # * New: Frame #-------------------------------------------------------------------- def self.frame @@frame end #-------------------------------------------------------------------- # * New: Set Pattern #-------------------------------------------------------------------- def self.pattern=(pattern) @@pattern = pattern end #-------------------------------------------------------------------- # * New: Pattern #-------------------------------------------------------------------- def self.pattern @@pattern end #-------------------------------------------------------------------- # * New: Set Width #-------------------------------------------------------------------- def self.width=(width) @@mouse_viewport.rect.width = width end #-------------------------------------------------------------------- # * New: Width #-------------------------------------------------------------------- def self.width @@mouse_viewport.rect.width end #-------------------------------------------------------------------- # * New: Set Height #-------------------------------------------------------------------- def self.height=(height) @@mouse_viewport.rect.height = height end #-------------------------------------------------------------------- # * New: Height #-------------------------------------------------------------------- def self.height @@mouse_viewport.rect.height end #-------------------------------------------------------------------- # * New: Mouse Coordinates #-------------------------------------------------------------------- def self.mouse_coords return [-1, -1] if get_os == :unknown lpPoint = "\0" * 8 GETCURSORPOS.call(lpPoint) success = SCREENTOCLIENT.call(GETACTIVEWINDOW.call, lpPoint) coord = lpPoint.unpack("ll") return coord end #-------------------------------------------------------------------- # * New: x-coordinate #-------------------------------------------------------------------- def self.x mouse_coords[0] end #-------------------------------------------------------------------- # * New: y-coordinate #-------------------------------------------------------------------- def self.y mouse_coords[1] end #-------------------------------------------------------------------- # * New: Toggles System Cursor #-------------------------------------------------------------------- def self.show_cursor(show) SHOWCURSOR.call(show ? 1 : 0) end #-------------------------------------------------------------------- # * New: Checks If Mouse Is In Screen #-------------------------------------------------------------------- def self.in_screen? x >= 0 && x < Graphics.width && y >= 0 && y < Graphics.height end #-------------------------------------------------------------------- # * New: Checks If Left Mouse Button Is Down #-------------------------------------------------------------------- def self.left_press? Keyboard.press?(Keys::M_LEFT) end #-------------------------------------------------------------------- # * New: Checks If Left Mouse Button Is Triggered #-------------------------------------------------------------------- def self.left_trigger? Keyboard.trigger?(Keys::M_LEFT) end #-------------------------------------------------------------------- # * New: Checks If Right Mouse Button Is Down #-------------------------------------------------------------------- def self.right_press? Keyboard.press?(Keys::M_RIGHT) end #-------------------------------------------------------------------- # * New: Checks If Right Mouse Button Is Triggered #-------------------------------------------------------------------- def self.right_trigger? Keyboard.trigger?(Keys::M_RIGHT) end #-------------------------------------------------------------------- # * New: Checks If Middle Mouse Button Is Down #-------------------------------------------------------------------- def self.middle_press? Keyboard.press?(Keys::M_MIDDLE) end #-------------------------------------------------------------------- # * New: Checks If Middle Mouse Button Is Triggered #-------------------------------------------------------------------- def self.middle_trigger? Keyboard.trigger?(Keys::M_MIDDLE) end #-------------------------------------------------------------------- # * New: Checks Custom Mouse Pointer Visibility #-------------------------------------------------------------------- def self.visible @@mouse_pointer.visible end #-------------------------------------------------------------------- # * New: Sets Custom Mouse Pointer Visibility #-------------------------------------------------------------------- def self.visible=(value) @@mouse_pointer.visible = value end end case get_os when :win32 #====================================================================== # ** XInputGamepad #---------------------------------------------------------------------- # The module that handles XInput compatible gamepads. #====================================================================== module XInputGamepad XINPUTGETSTATE = Win32API.new("xinput1_3", "XInputGetState", 'LP', 'L') X_DPAD_UP = 0 X_DPAD_DOWN = 1 X_DPAD_LEFT = 2 X_DPAD_RIGHT = 3 X_START = 4 X_BACK = 5 X_LTHUMB = 6 X_RTHUMB = 7 X_LSHOULDER = 8 X_RSHOULDER = 9 X_A = 12 X_B = 13 X_X = 14 X_Y = 15 X_SLTRIGGER = 16 X_SRTRIGGER = 17 X_STHUMBL_LEFT = 18 X_STHUMBL_RIGHT = 19 X_STHUMBL_DOWN = 20 X_STHUMBL_UP = 21 X_STHUMBR_LEFT = 22 X_STHUMBR_RIGHT = 23 X_STHUMBR_DOWN = 24 X_STHUMBR_UP = 25 X_S_LTRIGGER = :ltrigger X_S_RTRIGGER = :rtrigger X_S_THUMBLX = :thumblx X_S_THUMBLY = :thumbly X_S_THUMBRX = :thumbrx X_S_THUMBRY = :thumbry X_S_THUMBL = :thumbl X_S_THUMBR = :thumbr #------------------------------------------------------------------ # * New: Sliders #------------------------------------------------------------------ def self.sliders slist = {} slist[X_SLTRIGGER] = :ltrigger slist[X_SRTRIGGER] = :rtrigger slist[X_STHUMBL_LEFT] = :thumblx slist[X_STHUMBL_RIGHT] = :thumblx slist[X_STHUMBL_DOWN] = :thumbly slist[X_STHUMBL_UP] = :thumbly slist[X_STHUMBR_LEFT] = :thumbrx slist[X_STHUMBR_RIGHT] = :thumbrx slist[X_STHUMBR_DOWN] = :thumbry slist[X_STHUMBR_UP] = :thumbry slist[:thumblx] = :thumbl slist[:thumbly] = :thumbl slist[:thumbrx] = :thumbr slist[:thumbry] = :thumbr slist end #------------------------------------------------------------------ # * New: Linked Sliders # Handy for in-game key binding. #------------------------------------------------------------------ def self.linked_sliders slist = {} slist[:thumblx] = [X_STHUMBL_LEFT, X_STHUMBL_RIGHT] slist[:thumbly] = [X_STHUMBL_DOWN, X_STHUMBL_UP] slist[:thumbrx] = [X_STHUMBR_LEFT, X_STHUMBR_RIGHT] slist[:thumbry] = [X_STHUMBR_DOWN, X_STHUMBR_UP] slist end #------------------------------------------------------------------ # * New: Sticks #------------------------------------------------------------------ def self.sticks slist = [] slist.push(:thumbl) slist.push(:thumbr) end #------------------------------------------------------------------ # * New: Button Range #------------------------------------------------------------------ def self.get_button_range return Array.new(0..25) end @@gamepad = Array.new(4) #------------------------------------------------------------------ # * New: Initialization Gamepad #------------------------------------------------------------------ def self.init_gamepad 4.times do |padno| @@gamepad[padno] = {} pad = @@gamepad[padno] pad[:no_response_timer] = 0 pad[:press] = [false] * 26 pad[:repeat] = [false] * 26 pad[:trigger] = [false] * 26 pad[:press_time] = [0] * 26 pad[:slider] = {} pad[:slider][:ltrigger] = 0 pad[:slider][:rtrigger] = 0 pad[:slider][:thumblx] = 0 pad[:slider][:thumbly] = 0 pad[:slider][:thumbrx] = 0 pad[:slider][:thumbry] = 0 pad[:threshold] = {} pad[:threshold][:ltrigger] = 128 pad[:threshold][:rtrigger] = 128 pad[:threshold][:thumbl] = 12000 pad[:threshold][:thumbr] = 12000 pad[:deadzone] = {} pad[:deadzone][:ltrigger] = 30 pad[:deadzone][:rtrigger] = 30 pad[:deadzone][:thumbl] = 7849 pad[:deadzone][:thumbr] = 8689 end end init_gamepad #------------------------------------------------------------------ # * New: Update Gamepad #------------------------------------------------------------------ def self.update 4.times do |padno| xinput_state = "\0" * 16 error = XINPUTGETSTATE.call(padno, xinput_state) pad = @@gamepad[padno] pad[:no_response_timer] = [pad[:no_response_timer] + 1, 300].min next unless error == 0 pad[:no_response_timer] = 0 xis_data = xinput_state.unpack("LSCCssss") buttons = xis_data[1] pad[:slider][:ltrigger] = xis_data[2] pad[:slider][:rtrigger] = xis_data[3] pad[:slider][:thumblx] = xis_data[4] pad[:slider][:thumbly] = xis_data[5] pad[:slider][:thumbrx] = xis_data[6] pad[:slider][:thumbry] = xis_data[7] trigs = [:ltrigger, :rtrigger] slides = [:thumblx, :thumbly, :thumbrx, :thumbry] slide_thres = [:thumbl, :thumbr] 26.times do |button| trigger = false if button < 16 trigger = buttons & (1 << button) != 0 elsif button < 18 trigger = pad[:slider][trigs[button - 16]] >= pad[:threshold][trigs[button - 16]] else thres = pad[:threshold][slide_thres[(button - 18) / 4]] val = pad[:slider][slides[(button - 18) / 2]] trigger = val * ((button - 18) % 2 == 0 ? -1 : 1) >= thres.abs end unless trigger pad[:press][button] = false pad[:repeat][button] = false pad[:trigger][button] = false pad[:press_time][button] = 0 next end old_val = pad[:press_time][button] pad[:press_time][button]+= 1 pad[:press][button] = true pad[:trigger][button] = old_val == 0 pad[:repeat][button] = old_val == 0 || (old_val >= 32 && old_val % 2 == 0) end end end #------------------------------------------------------------------ # * New: Check Pressed #------------------------------------------------------------------ def self.press?(padno, key) return @@gamepad[padno][:press][key] unless key.kind_of?(Array) key.each do |k| unless k.kind_of?(Array) state = @@gamepad[padno][:press][k] return true if state next end state = true k.each do |sk| state = @@gamepad[padno][:press][sk] break unless state end return true if state end return false end #------------------------------------------------------------------ # * New: Check Repeated #------------------------------------------------------------------ def self.repeat?(padno, key) return @@gamepad[padno][:repeat][key] unless key.kind_of?(Array) key.each do |k| unless k.kind_of?(Array) state = @@gamepad[padno][:repeat][k] return true if state next end state = true k.each do |sk| state = @@gamepad[padno][:repeat][sk] break unless state end return true if state end return false end #------------------------------------------------------------------ # * New: Check Triggered #------------------------------------------------------------------ def self.trigger?(padno, key) return @@gamepad[padno][:trigger][key] unless key.kind_of?(Array) key.each do |k| unless k.kind_of?(Array) state = @@gamepad[padno][:trigger][k] return true if state next end state = true k.each do |sk| state = @@gamepad[padno][:trigger][sk] break unless state end return true if state end return false end #------------------------------------------------------------------ # * New: Time Pressed #------------------------------------------------------------------ def self.press_time(padno, key) return @@gamepad[padno][:press_time][key] end #------------------------------------------------------------------ # * New: Get Slider Value #------------------------------------------------------------------ def self.get_slider(padno, key, no_deadzone = false, no_normalize = false) val = 0 div = 0 dez = 0 pad = @@gamepad[padno] if [:ltrigger, :rtrigger].include?(key) val = pad[:slider][key] div = 255.0 dez = pad[:deadzone][key] unless no_deadzone val = [val, div].min val-= dez val = [val, 0].max val = val / (div - dez) * (no_normalize ? div : 1) else div = 32767.0 use = [:thumbrx, :thumbry, :thumbr] use = [:thumblx, :thumbly, :thumbl] if [:thumblx, :thumbly, :thumbl].include?(key) sx = pad[:slider][use[0]] sy = pad[:slider][use[1]] val = Math.hypot(sx, sy) dez = pad[:deadzone][use[2]] unless no_deadzone angle = Math.atan2(sy, sx) val = [val, div].min val-= dez val = [val, 0].max val = val / (div - dez) * (no_normalize ? div : 1) val = Math.cos(angle) * val if key == use[0] val = Math.sin(angle) * val if key == use[1] end return val end #------------------------------------------------------------------ # * New: Get Trigger #------------------------------------------------------------------ def self.get_thumb_angle(padno, key) use = [:thumbrx, :thumbry] use = [:thumblx, :thumbly] if [:thumblx, :thumbly, :thumbl].include?(key) sx = @@gamepad[padno][:slider][use[0]] sy = @@gamepad[padno][:slider][use[1]] angle = Math.atan2(sy, sx) return angle end #------------------------------------------------------------------ # * New: Get Threshold #------------------------------------------------------------------ def self.get_threshold(padno, key) return @@gamepad[padno][:threshold][key] end #------------------------------------------------------------------ # * New: Set Threshold #------------------------------------------------------------------ def self.set_threshold(padno, key, value) @@gamepad[padno][:threshold][key] = value end #------------------------------------------------------------------ # * New: Get Dead Zone #------------------------------------------------------------------ def self.get_deadzone(padno, key) return @@gamepad[padno][:deadzone][key] end #------------------------------------------------------------------ # * New: Set Dead Zone #------------------------------------------------------------------ def self.set_deadzone(padno, key, value) key = :thumbl if [:thumblx, :thumbly].include?(key) key = :thumbr if [:thumbrx, :thumbry].include?(key) @@gamepad[padno][:deadzone][key] = value end end end #======================================================================== # ** Gamepad #------------------------------------------------------------------------ # The gamepad. #======================================================================== module Gamepad @@gamepads = {} @@gamepads[:none] = nil if get_os == :win32 @@gamepads[:xinput] = XInputGamepad end @@current_gamepad = [nil, 0] @@padbind = {} @@padbind[:LEFT]||= [] @@padbind[:RIGHT]||= [] @@padbind[:UP]||= [] @@padbind[:DOWN]||= [] @@padbind[:A]||= [] @@padbind[:B]||= [] @@padbind[:C]||= [] @@padbind[:X]||= [] @@padbind[:Y]||= [] @@padbind[:Z]||= [] @@padbind[:L]||= [] @@padbind[:R]||= [] @@padbind[:SHIFT]||= [] @@padbind[:CTRL]||= [] @@padbind[:ALT]||= [] @@padbind[:F5]||= [] @@padbind[:F6]||= [] @@padbind[:F7]||= [] @@padbind[:F8]||= [] @@padbind[:F9]||= [] #-------------------------------------------------------------------- # * New: Set Current Gamepad #-------------------------------------------------------------------- def self.set_gamepad(sym, num) return if sym.nil? @@current_gamepad[0] = @@gamepads[sym] @@current_gamepad[1] = num end set_gamepad(CXJ::INPEX::DEFAULT_GAMEPAD_TYPE, CXJ::INPEX::DEFAULT_GAMEPAD_NUM) unless @@current_gamepad[0].nil? CXJ::INPEX::DEFAULT_BIND_GAMEPAD.each_pair do |key, val| val.each_index do |i| val[i] = @@current_gamepad[0].const_get(val[i]) if val[i].kind_of?(Symbol) end @@padbind[key]||= [] @@padbind[key].concat(val) end end #-------------------------------------------------------------------- # * New: Button Range #-------------------------------------------------------------------- def self.get_button_range return @@current_gamepad[0].get_button_range unless @@current_gamepad[0].nil? end #-------------------------------------------------------------------- # * New: Update #-------------------------------------------------------------------- def self.update @@current_gamepad[0].update unless @@current_gamepad[0].nil? end #-------------------------------------------------------------------- # * New: Check Pressed #-------------------------------------------------------------------- def self.press?(key) return false if @@current_gamepad[0].nil? return false if @@padbind[key].nil? key = @@padbind[key] if key.kind_of?(Symbol) return @@current_gamepad[0].press?(@@current_gamepad[1], key) end #-------------------------------------------------------------------- # * New: Check Repeated #-------------------------------------------------------------------- def self.repeat?(key) return false if @@current_gamepad[0].nil? return false if @@padbind[key].nil? key = @@padbind[key] if key.kind_of?(Symbol) return @@current_gamepad[0].repeat?(@@current_gamepad[1], key) end #-------------------------------------------------------------------- # * New: Check Triggered #-------------------------------------------------------------------- def self.trigger?(key) return false if @@current_gamepad[0].nil? return false if @@padbind[key].nil? key = @@padbind[key] if key.kind_of?(Symbol) return @@current_gamepad[0].trigger?(@@current_gamepad[1], key) end #-------------------------------------------------------------------- # * New: Time Pressed #-------------------------------------------------------------------- def self.press_time(key) return 0 if @@current_gamepad[0].nil? return 0 if @@padbind[key].nil? key = @@padbind[key] if key.kind_of?(Symbol) return @@current_gamepad[0].press_time(@@current_gamepad[1], key) end #-------------------------------------------------------------------- # * New: Get Slider #-------------------------------------------------------------------- def self.get_slider(key) return 0 if @@current_gamepad[0].nil? return 0 if @@padbind[key].nil? key = @@padbind[key] if key.kind_of?(Symbol) key = @@current_gamepad[0].sliders[key] return nil if key.nil? return @@current_gamepad[0].get_slider(@@current_gamepad[1], key) end #-------------------------------------------------------------------- # * New: Get Tumb Stick Angle #-------------------------------------------------------------------- def self.get_thumb_angle(key) return 0 if @@current_gamepad[0].nil? return 0 if @@padbind[key].nil? key = @@padbind[key] if key.kind_of?(Symbol) return @@current_gamepad[0].get_thumb_angle(@@current_gamepad[1], key) end #-------------------------------------------------------------------- # * New: Bind Key #-------------------------------------------------------------------- def self.bind_gamepad(symbol, key) @@padbind[symbol]||= [] @@padbind[symbol].push(key) unless @@padbind[symbol].include?(key) end #-------------------------------------------------------------------- # * New: Unbind Key #-------------------------------------------------------------------- def self.unbind_gamepad(symbol, key = nil) if key.nil? @@padbind[symbol] = [] else @@padbind[symbol].delete(key) end end #-------------------------------------------------------------------- # * New: Get Directon (Up, Down, Left, Right) #-------------------------------------------------------------------- def self.dir4 return 0 if @@current_gamepad[0].nil? pad_handle = @@current_gamepad[0] padno = @@current_gamepad[1] dir_h = [:LEFT, :RIGHT] dir_v = [:UP, :DOWN] shortest = [nil, 0, nil] dir_h.each_index do |i| @@padbind[dir_h[i]].each do |k| if pad_handle.press?(padno, k) pr = pad_handle.press_time(padno, k) shortest = [k, pr, dir_h[i]] if shortest[0].nil? || shortest[1] > pr end end end dir_k_h = shortest shortest = [nil, 0, nil] dir_v.each_index do |i| @@padbind[dir_v[i]].each do |k| if pad_handle.press?(padno, k) pr = pad_handle.press_time(padno, k) shortest = [k, pr, dir_v[i]] if shortest[0].nil? || shortest[1] > pr end end end dir_k_v = shortest return 0 if(dir_k_h[2].nil? && dir_k_v[2].nil?) cdir = (dir_k_h[1] < dir_k_v[1] ? dir_k_h[2] : dir_k_v[2]) cdir = (!dir_k_h[2].nil? && !dir_k_v[2].nil? ? cdir : !dir_k_h[2].nil? ? dir_k_h[2] : dir_k_v[2]) case cdir when :LEFT return 4 when :RIGHT return 6 when :UP return 8 when :DOWN return 2 end return 0 end #-------------------------------------------------------------------- # * New: Get Direction (All Eight) #-------------------------------------------------------------------- def self.dir8 return 0 if @@current_gamepad[0].nil? pad_handle = @@current_gamepad[0] padno = @@current_gamepad[1] dir_h = [:LEFT, :RIGHT] dir_v = [:UP, :DOWN] shortest = [nil, 0, nil] dir_h.each_index do |i| @@padbind[dir_h[i]].each do |k| if pad_handle.press?(padno, k) pr = pad_handle.press_time(padno, k) shortest = [k, pr, dir_h[i]] if shortest[0].nil? || shortest[1] > pr end end end dir_k_h = shortest shortest = [nil, 0, nil] dir_v.each_index do |i| @@padbind[dir_v[i]].each do |k| if pad_handle.press?(padno, k) pr = pad_handle.press_time(padno, k) shortest = [k, pr, dir_v[i]] if shortest[0].nil? || shortest[1] > pr end end end dir_k_v = shortest hmod = (dir_k_h[2].nil? ? 0 : dir_k_h[2] == :LEFT ? -1 : 1) vmod = (dir_k_v[2].nil? ? 0 : dir_k_v[2] == :DOWN ? -3 : 3) return 0 if hmod == 0 && vmod == 0 return hmod + vmod + 5 end #-------------------------------------------------------------------- # * New: Get Shortest Time Pressed On Directions #-------------------------------------------------------------------- def self.dir_shortest_time return -1 if @@current_gamepad[0].nil? dirs = [:LEFT, :RIGHT, :UP, :DOWN] shortest = [nil, 0] pad_handle = @@current_gamepad[0] padno = @@current_gamepad[1] dirs.each do |d| @@padbind[d].each do |k| if pad_handle.press?(padno, k) pr = pad_handle.press_time(padno, k) shortest = [k, pr] if shortest[0].nil? || shortest[1] > pr end end end return -1 if shortest[0].nil? return shortest[1] end end #======================================================================== # ** Keyboard #------------------------------------------------------------------------ # The keyboard. #======================================================================== module Keyboard case get_os when :win32 include CXJ::INPEX::WIN32 else include CXJ::INPEX::UNKNOWN end @@keybind = {} @@press_state = [] @@repeat_state = [] @@trigger_state = [] @@press_time = [] @@keybind[:LEFT]||= [] @@keybind[:RIGHT]||= [] @@keybind[:UP]||= [] @@keybind[:DOWN]||= [] @@keybind[:A]||= [] @@keybind[:B]||= [] @@keybind[:C]||= [] @@keybind[:X]||= [] @@keybind[:Y]||= [] @@keybind[:Z]||= [] @@keybind[:L]||= [] @@keybind[:R]||= [] @@keybind[:SHIFT]||= [] @@keybind[:CTRL]||= [] @@keybind[:ALT]||= [] @@keybind[:F5]||= [] @@keybind[:F6]||= [] @@keybind[:F7]||= [] @@keybind[:F8]||= [] @@keybind[:F9]||= [] CXJ::INPEX::DEFAULT_BIND.each_pair do |key, val| @@keybind[key]||= [] @@keybind[key].concat(val) end #-------------------------------------------------------------------- # * New: Update #-------------------------------------------------------------------- def self.update if @@press_state.empty? 256.times do |i| @@press_state[i] = 0 @@repeat_state[i] = false @@trigger_state[i] = false @@press_time[i] = 0 end end 256.times do |i| old_state = @@press_state[i] new_state = get_key_state(i) @@press_state[i] = new_state @@repeat_state[i] = false @@trigger_state[i] = false if new_state & 0x8000 > 0 @@press_time[i]+= 1 @@repeat_state[i] = new_state & 0x0001 > 0 @@trigger_state[i] = old_state & 0x8000 == 0 if new_state & 0x0001 > 0 else @@press_time[i] = 0 end end end #-------------------------------------------------------------------- # * New: Get Key State #-------------------------------------------------------------------- def self.get_key_state(key) return 0 if get_os == :unknown GETASYNCKEYSTATE.call(key) end #-------------------------------------------------------------------- # * New: Check Pressed #-------------------------------------------------------------------- def self.press?(key) if key.instance_of?(Symbol) key = @@keybind[key] if @@keybind.has_key?(key) key = CXJ::INPEX::CORE::Keys.const_get(key) if key.instance_of?(Symbol) && CXJ::INPEX::CORE::Keys.constants(false).include?(key) return false if key.kind_of?(Symbol) end return @@press_state[key] & 0x8000 > 0 unless key.kind_of?(Array) key.each do |s_key| if s_key.kind_of?(Array) is_trigger = true s_key.each do |ss_key| ss_key = CXJ::INPEX::CORE::Keys.const_get(ss_key) if ss_key.instance_of?(Symbol) && CXJ::INPEX::CORE::Keys.constants(false).include?(ss_key) is_trigger = press?(ss_key) break if !is_trigger end return true if is_trigger else s_key = CXJ::INPEX::CORE::Keys.const_get(s_key) if s_key.instance_of?(Symbol) && CXJ::INPEX::CORE::Keys.constants(false).include?(s_key) return true if press?(s_key) end end return false end #-------------------------------------------------------------------- # * New: Check Repeated #-------------------------------------------------------------------- def self.repeat?(key) if key.instance_of?(Symbol) key = @@keybind[key] if @@keybind.has_key?(key) key = CXJ::INPEX::CORE::Keys.const_get(key) if key.instance_of?(Symbol) && CXJ::INPEX::CORE::Keys.constants(false).include?(key) return false if key.kind_of?(Symbol) end return @@repeat_state[key] unless key.kind_of?(Array) key.each do |s_key| s_key = s_key[0] if s_key.kind_of?(Array) && s_key.size == 1 next if s_key.kind_of?(Array) s_key = CXJ::INPEX::CORE::Keys.const_get(s_key) if s_key.instance_of?(Symbol) && CXJ::INPEX::CORE::Keys.constants(false).include?(s_key) return true if repeat?(s_key) end return false end #-------------------------------------------------------------------- # * New: Check Triggered #-------------------------------------------------------------------- def self.trigger?(key) if key.instance_of?(Symbol) key = @@keybind[key] if @@keybind.has_key?(key) key = CXJ::INPEX::CORE::Keys.const_get(key) if key.instance_of?(Symbol) && CXJ::INPEX::CORE::Keys.constants(false).include?(key) return false if key.kind_of?(Symbol) end return @@trigger_state[key] unless key.kind_of?(Array) key.each do |s_key| s_key = s_key[0] if s_key.kind_of?(Array) && s_key.size == 1 next if s_key.kind_of?(Array) s_key = CXJ::INPEX::CORE::Keys.const_get(s_key) if s_key.instance_of?(Symbol) && CXJ::INPEX::CORE::Keys.constants(false).include?(s_key) return true if trigger?(s_key) end return false end #-------------------------------------------------------------------- # * New: Get Time Pressed #-------------------------------------------------------------------- def self.press_time(key) if key.instance_of?(Symbol) key = @@keybind[key] if @@keybind.has_key?(key) key = CXJ::INPEX::CORE::Keys.const_get(key) if key.instance_of?(Symbol) && CXJ::INPEX::CORE::Keys.constants(false).include?(key) return 0 if key.kind_of?(Symbol) end return @@press_time[key] unless key.kind_of?(Array) highest = 0 key.each do |s_key| if s_key.kind_of?(Array) lowest = nil s_key.each do |ss_key| ss_key = CXJ::INPEX::CORE::Keys.const_get(ss_key) if ss_key.instance_of?(Symbol) lowest = @@press_time[ss_key] if lowest.nil? lowest = [lowest, @@press_time[ss_key]].min end highest = [highest, lowest].max else s_key = CXJ::INPEX::CORE::Keys.const_get(s_key) if s_key.instance_of?(Symbol) && CXJ::INPEX::CORE::Keys.constants(false).include?(s_key) highest = [highest, @@press_time[s_key]].max end end return highest end #-------------------------------------------------------------------- # * New: Bind Key #-------------------------------------------------------------------- def self.bind_keyboard(symbol, key) @@keybind[symbol]||= [] @@keybind[symbol].push(key) unless @@keybind[symbol].include?(key) end #-------------------------------------------------------------------- # * New: Unbind Key #-------------------------------------------------------------------- def self.unbind_keyboard(symbol, key = nil) if key.nil? @@keybind[symbol] = [] else @@keybind[symbol].delete(key) end end #-------------------------------------------------------------------- # * New: Lists Bound Keys #-------------------------------------------------------------------- def self.get_bound_keys(symbol) @@keybind[symbol]||= [] return Array.new(@@keybind[symbol]) if @@keybind.has_key?(symbol) end #-------------------------------------------------------------------- # * New: Get Direction (Up, Down, Left, Right) #-------------------------------------------------------------------- def self.dir4 dirs_h = [:LEFT, :RIGHT] dirs_v = [:UP, :DOWN] longest_h = [nil, 0] longest_v = [nil, 0] (dirs_h + dirs_v).each do |dir| duration = press_time(dir) if dirs_h.include?(dir) if duration > longest_h[1] unless longest_h[1] > 0 longest_h = [dir, duration] else longest_h = [nil, 0] end end else if duration > longest_v[1] unless longest_v[1] > 0 longest_v = [dir, duration] else longest_v = [nil, 0] end end end end return 0 if longest_h[1] == 0 && longest_v[1] == 0 longest = longest_h longest = longest_v if (longest_h[1] > longest_v[1] && longest_v[1] > 0) || longest_h[1] == 0 case longest[0] when :LEFT return 4 when :RIGHT return 6 when :UP return 8 when :DOWN return 2 end end #-------------------------------------------------------------------- # * New: Get Direction (All Eight) #-------------------------------------------------------------------- def self.dir8 h = (press?(:LEFT) == press?(:RIGHT) ? 0 : press?(:LEFT) ? -1 : 1) v = (press?(:UP) == press?(:DOWN) ? 0 : press?(:UP) ? 3 : -3) return 0 if h == v return 5 + h + v end #-------------------------------------------------------------------- # * New: Get Shortest Time Pressed On Directions #-------------------------------------------------------------------- def self.dir_shortest_time dirs = [:LEFT, :RIGHT, :UP, :DOWN] shortest = [nil, 0] dirs.each do |d| @@keybind[d].each do |k| if press?(k) pr = press_time(k) shortest = [k, pr] if shortest[0].nil? || shortest[1] > pr end end end return -1 if shortest[0].nil? return shortest[1] end #-------------------------------------------------------------------- # * New: Get All Triggered Keys #-------------------------------------------------------------------- def self.all_trigger(*triggers) list = [] 256.times do |i| unless triggers.nil? next if triggers.include?(:no_lr) && (0xA0..0xA5).include?(i) next if triggers.include?(:only_lr) && (0x10..0x12).include?(i) next if triggers.include?(:no_mouse) && [0x01, 0x02, 0x04].include?(i) end list.push(i) if trigger?(i) end return list end end end include CXJ::INPEX::CORE if !INCLUDE_CORE end end include CXJ::INPEX::CORE if CXJ::INPEX::INCLUDE_CORE #============================================================================== # ** Window_SimpleKeyTest #------------------------------------------------------------------------------ # This adds a window that can catch key presses. #============================================================================== class Window_SimpleKeyTest < Window_Base #-------------------------------------------------------------------------- # * New: Initialization #-------------------------------------------------------------------------- def initialize(keys, triggers = [:no_lr, :no_mouse], *additional) w = 160 h = 90 x = (Graphics.width - w) / 2 y = (Graphics.height - h) / 2 super(x, y, w, h) draw_text(0, 0, contents.width, contents.height / 2, "Press a key", 1) @keys = keys @triggers = triggers @triggers = [@triggers] unless @triggers.kind_of?(Array) @triggers.concat(additional) @timer = Graphics.frame_rate * 10 @timer_rect = Rect.new(0, contents.height / 2, contents.width, contents.height / 2) end #-------------------------------------------------------------------------- # * New: Frame Update #-------------------------------------------------------------------------- def update super unless @closing || close? @timer-= 1 contents.clear_rect(@timer_rect) draw_text(@timer_rect, "(" + (@timer / Graphics.frame_rate + 1).to_s + ")", 1) keys = CXJ::INPEX::CORE::Keyboard.all_trigger(*@triggers) unless keys.nil? || keys.empty? @keys.concat(keys) close end close unless @timer > 0 end end end if CXJ::INPEX::HOOK_KEYBOARD_TO_INPUT || CXJ::INPEX::HOOK_GAMEPAD_TO_INPUT #============================================================================ # ** Input #============================================================================ module Input class << self @@enabled = {} @@dir_enabled = [true, true, true, true, true, true, true, true, true, true] #---------------------------------------------------------------------- # * Alias: Update Input #---------------------------------------------------------------------- alias input_update_cxj_inpex update def update if CXJ::INPEX::HOOK_GAMEPAD_TO_INPUT Gamepad.update if CXJ::INPEX::INCLUDE_CORE CXJ::INPEX::Gamepad.update if !CXJ::INPEX::INCLUDE_CORE end if CXJ::INPEX::HOOK_KEYBOARD_TO_INPUT Keyboard.update if CXJ::INPEX::INCLUDE_CORE CXJ::INPEX::Keyboard.update if !CXJ::INPEX::INCLUDE_CORE end input_update_cxj_inpex if CXJ::INPEX::ENABLE_COMPATIBILITY end #---------------------------------------------------------------------- # * Alias: Pressed #---------------------------------------------------------------------- alias input_press_cxj_inpex? press? def press?(sym) return false unless is_key_enabled?(sym) if CXJ::INPEX::HOOK_GAMEPAD_TO_INPUT val = Gamepad.press?(sym) if CXJ::INPEX::INCLUDE_CORE val = CXJ::INPEX::Gamepad.press?(sym) if !CXJ::INPEX::INCLUDE_CORE end if CXJ::INPEX::HOOK_KEYBOARD_TO_INPUT && !val val = Keyboard.press?(sym) if CXJ::INPEX::INCLUDE_CORE val = CXJ::INPEX::Keyboard.press?(sym) if !CXJ::INPEX::INCLUDE_CORE end val = input_press_cxj_inpex?(sym) if !val && CXJ::INPEX::ENABLE_COMPATIBILITY return val end #---------------------------------------------------------------------- # * Alias: Repeated #---------------------------------------------------------------------- alias input_repeat_cxj_inpex? repeat? def repeat?(sym) return false unless is_key_enabled?(sym) if CXJ::INPEX::HOOK_GAMEPAD_TO_INPUT val = Gamepad.repeat?(sym) if CXJ::INPEX::INCLUDE_CORE val = CXJ::INPEX::Gamepad.repeat?(sym) if !CXJ::INPEX::INCLUDE_CORE end if CXJ::INPEX::HOOK_KEYBOARD_TO_INPUT && !val val = Keyboard.repeat?(sym) if CXJ::INPEX::INCLUDE_CORE val = CXJ::INPEX::Keyboard.repeat?(sym) if !CXJ::INPEX::INCLUDE_CORE end val = input_repeat_cxj_inpex?(sym) if !val && CXJ::INPEX::ENABLE_COMPATIBILITY return val end #---------------------------------------------------------------------- # * Alias: Triggered #---------------------------------------------------------------------- alias input_trigger_cxj_inpex? trigger? def trigger?(sym) return false unless is_key_enabled?(sym) if CXJ::INPEX::HOOK_GAMEPAD_TO_INPUT val = Gamepad.trigger?(sym) if CXJ::INPEX::INCLUDE_CORE val = CXJ::INPEX::Gamepad.trigger?(sym) if !CXJ::INPEX::INCLUDE_CORE end if CXJ::INPEX::HOOK_KEYBOARD_TO_INPUT && !val val = Keyboard.trigger?(sym) if CXJ::INPEX::INCLUDE_CORE val = CXJ::INPEX::Keyboard.trigger?(sym) if !CXJ::INPEX::INCLUDE_CORE end val = input_trigger_cxj_inpex?(sym) if !val && CXJ::INPEX::ENABLE_COMPATIBILITY return val end #---------------------------------------------------------------------- # * Alias: Direction (Up, Down, Left, Right) #---------------------------------------------------------------------- alias input_dir4_cxj_inpex dir4 def dir4 shortest = -1 if CXJ::INPEX::HOOK_GAMEPAD_TO_INPUT if CXJ::INPEX::INCLUDE_CORE shortest = Gamepad.dir_shortest_time val = Gamepad.dir4 else shortest = CXJ::INPEX::Gamepad.dir_shortest_time val = CXJ::INPEX::Keyboard.dir4 end end if CXJ::INPEX::HOOK_KEYBOARD_TO_INPUT if CXJ::INPEX::INCLUDE_CORE s_key = Keyboard.dir_shortest_time val = Keyboard.dir4 if val == 0 || (shortest > -1 && s_key > -1 && s_key <= shortest) else s_key = CXJ::INPEX::Keyboard.dir_shortest_time val = CXJ::INPEX::Keyboard.dir4 if val == 0 || (shortest > -1 && s_key > -1 && s_key <= shortest) end end val = input_dir4_cxj_inpex if val == 0 && CXJ::INPEX::ENABLE_COMPATIBILITY return 0 unless(get_dir_enabled(val)) return val end #---------------------------------------------------------------------- # * Alias: Direction (All Eight) #---------------------------------------------------------------------- alias input_dir8_cxj_inpex dir8 def dir8 if CXJ::INPEX::HOOK_KEYBOARD_TO_INPUT val = Keyboard.dir8 if CXJ::INPEX::INCLUDE_CORE val = CXJ::INPEX::Keyboard.dir8 if !CXJ::INPEX::INCLUDE_CORE end val = input_dir8_cxj_inpex if val == 0 && CXJ::INPEX::ENABLE_COMPATIBILITY return 0 unless(get_dir_enabled(val)) return val end #---------------------------------------------------------------------- # * New: Set Enabled Status Of Key #---------------------------------------------------------------------- def set_key_enabled(sym, status) @@enabled[sym] = status end #---------------------------------------------------------------------- # * New: Get Enabled Status Of Key #---------------------------------------------------------------------- def is_key_enabled?(sym) @@enabled[sym] = true unless @@enabled.has_key?(sym) return @@enabled[sym] end #---------------------------------------------------------------------- # * New: Set Enabled Status Of Direction #---------------------------------------------------------------------- def set_dir_enabled(dir, status) @@dir_enabled[dir] = status end #---------------------------------------------------------------------- # * New: Get Enabled Status Of Direction #---------------------------------------------------------------------- def get_dir_enabled(dir) return @@dir_enabled[dir] end end end end if CXJ::INPEX::ENABLE_CUSTOM_POINTER #============================================================================ # ** SceneManager #---------------------------------------------------------------------------- # This module manages scene transitions. For example, it can handle # hierarchical structures such as calling the item screen from the main menu # or returning from the item screen to the main menu. #============================================================================ module SceneManager class << self #---------------------------------------------------------------------- # * Alias: Create Snapshot to Use as Background #---------------------------------------------------------------------- alias scenemanager_snapshot_for_background_cxj_inpex snapshot_for_background def snapshot_for_background vis = CXJ::INPEX::CORE::Mouse.visible CXJ::INPEX::CORE::Mouse.visible = false scenemanager_snapshot_for_background_cxj_inpex CXJ::INPEX::CORE::Mouse.visible = vis end end end end #============================================================================== # ** Window_Base #------------------------------------------------------------------------------ # This is a super class of all windows within the game. #============================================================================== class Window_Base < Window #-------------------------------------------------------------------------- # * Alias: Preconvert Control Characters # As a rule, replace only what will be changed into text strings before # starting actual drawing. The character "\" is replaced with the escape # character (\e). #-------------------------------------------------------------------------- alias window_base_convert_escape_characters_cxj_inpex convert_escape_characters def convert_escape_characters(text) result = window_base_convert_escape_characters_cxj_inpex(text) result.gsub!(/\eBKEYI\[(\w+)\]/i) { get_bound_keys_icons($1) } result.gsub!(/\eBKEYI\[(\w+),(OR|AND)\]/i) { get_bound_keys_icons($1, ($2.upcase == "AND" ? true : false)) } result.gsub!(/\eKEYI\[(\w+)\]/i) { "\eKEY[" + $1.to_s + "]" } if CXJ::INPEX::KEYBOARD_ICONS.nil? || CXJ::INPEX::KEYBOARD_ICONS.empty? result.gsub!(/\eKEY\[(\d+)\]/i) { get_key_name($1.to_i) } result.gsub!(/\eKEY\[(\w+)\]/i) { get_key_name($1) } result.gsub!(/\eBKEY\[(\w+)\]/i) { get_bound_keys($1) } result.gsub!(/\eBKEY\[(\w+),(OR|AND)\]/i) { get_bound_keys($1, ($2.upcase == "AND" ? true : false)) } result end #-------------------------------------------------------------------------- # * Control Character Processing # code : the core of the control character # e.g. "C" in the case of the control character \C[1]. #-------------------------------------------------------------------------- alias window_base_process_escape_character_cxj_inpex process_escape_character def process_escape_character(code, text, pos) processed = false case code.upcase when "KEYI" line = text.slice!(/^\[((\d+)|(\w+))\]/i) unless line.nil? if $2.nil? get_key_icon($3, text, pos) else get_key_icon($2.to_i, text, pos) end end else window_base_process_escape_character_cxj_inpex(code, text, pos) end end #-------------------------------------------------------------------------- # * New: Get Key Name #-------------------------------------------------------------------------- def get_key_name(key) if key.kind_of?(String) key = CXJ::INPEX::CORE::Keys.const_get(key.to_sym) if CXJ::INPEX::CORE::Keys.constants(false).include?(key.to_sym) end if key.kind_of?(Symbol) key = CXJ::INPEX::CORE::Keys.const_get(key) if CXJ::INPEX::CORE::Keys.constants(false).include?(key) end return CXJ::INPEX::VOCAB_KEY_UNKNOWN + "_" + key.to_s unless key.kind_of?(Numeric) return CXJ::INPEX::CORE::Keys::KEY_STRING[key] unless CXJ::INPEX::CORE::Keys::KEY_STRING[key].nil? return CXJ::INPEX::VOCAB_KEY_UNKNOWN + "_" + key.to_s end #-------------------------------------------------------------------------- # * New: Get Bound Keys #-------------------------------------------------------------------------- def get_bound_keys(key, use_and = false) keys = CXJ::INPEX::CORE::Keyboard.get_bound_keys(key.to_sym) return CXJ::INPEX::VOCAB_UNDEFINED + "_" + key if keys.nil? || keys.empty? str = "" keys.each_index do |i| str+= ", " if i > 0 && i < keys.size - 1 str+= " " + (use_and ? CXJ::INPEX::VOCAB_AND : CXJ::INPEX::VOCAB_OR) + " " if keys.size > 1 && i == keys.size - 1 if keys[i].kind_of?(Array) keys[i].each_index do |j| str+= " + " if j > 0 str+= get_key_name(keys[i][j]) end else str+= get_key_name(keys[i]) end end return str end #-------------------------------------------------------------------------- # * New: Get Key Icon #-------------------------------------------------------------------------- def get_key_icon(key, text, pos) op = nil case get_os when :win32 op = CXJ::INPEX::WIN32 end if key.kind_of?(String) key = CXJ::INPEX::CORE::Keys.const_get(key.to_sym) if CXJ::INPEX::CORE::Keys.constants(false).include?(key.to_sym) end if key.kind_of?(Symbol) key = CXJ::INPEX::CORE::Keys.const_get(key) if CXJ::INPEX::CORE::Keys.constants(false).include?(key) end unless key.kind_of?(Numeric) text.gsub!(/^/) { get_key_name(key) } return end bitmap = Cache.normal_bitmap(CXJ::INPEX::KEYBOARD_ICONS) unless CXJ::INPEX::KEYBOARD_ICONS.nil? || CXJ::INPEX::KEYBOARD_ICONS.empty? w = bitmap.width / 16 h = CXJ::INPEX::DEFAULT_ICON_HEIGHT rect = Rect.new(key % 16 * w, key / 16 * h, w, h) CXJ::INPEX::CUSTOM_KEY_ICON.each_pair do |c_key, area| if c_key.kind_of?(Symbol) c_key = CXJ::INPEX::CORE::Keys.const_get(c_key) if CXJ::INPEX::CORE::Keys.constants(false).include?(c_key) end next unless c_key.kind_of?(Numeric) || c_key.kind_of?(String) if c_key.kind_of?(String) && !op.nil? chr = op::MAPVIRTUALKEY.call(key, 2) next if chr == 0 s_key = [chr].pack("C") if s_key == c_key rect = Rect.new(area[0], area[1], area[2], area[3]) w = area[2] break end else if key == c_key rect = Rect.new(area[0], area[1], area[2], area[3]) w = area[2] break end end end contents.blt(pos[:x], pos[:y], bitmap, rect) pos[:x] += w end #-------------------------------------------------------------------------- # * New: Get Bound Keys Icons #-------------------------------------------------------------------------- def get_bound_keys_icons(key, use_and = false) keys = CXJ::INPEX::CORE::Keyboard.get_bound_keys(key.to_sym) return CXJ::INPEX::VOCAB_UNDEFINED + "_" + key if keys.nil? || keys.empty? str = "" keys.each_index do |i| str+= ", " if i > 0 && i < keys.size - 1 str+= " " + (use_and ? CXJ::INPEX::VOCAB_AND : CXJ::INPEX::VOCAB_OR) + " " if keys.size > 1 && i == keys.size - 1 if keys[i].kind_of?(Array) keys[i].each_index do |j| str+= " + " if j > 0 str+= "\eKEYI[" + keys[i][j].to_s + "]" end else str+= "\eKEYI[" + keys[i].to_s + "]" end end return str end end if CXJ::INPEX::HOOK_MOUSE_TO_WINDOWS #============================================================================ # ** Window_Selectable #---------------------------------------------------------------------------- # This window class contains cursor movement and scroll functions. #============================================================================ class Window_Selectable < Window_Base #------------------------------------------------------------------------ # * Frame Update #------------------------------------------------------------------------ alias windows_selectable_update_cxj_inpex_test update def update windows_selectable_update_cxj_inpex_test return unless open? && active item_max.times do |i| r = Rect.new r.set(item_rect(i)) r.x+= x + padding r.y+= y + padding if Mouse.x >= r.x && Mouse.x <= r.x + r.width && Mouse.y >= r.y && Mouse.y <= r.y + r.height select(i) process_ok if ok_enabled? && Mouse.left_trigger? end end end end end #============================================================================== # ** Scene_Base #------------------------------------------------------------------------------ # This is a super class of all scenes within the game. #============================================================================== class Scene_Base #-------------------------------------------------------------------------- # * Alias: Main #-------------------------------------------------------------------------- alias scene_base_main_cxj_inpex main def main if CXJ::INPEX::DISABLE_F12_RESET begin scene_base_main_cxj_inpex rescue RGSSReset end else scene_base_main_cxj_inpex end end #-------------------------------------------------------------------------- # * Alias: Update Frame (Basic) #-------------------------------------------------------------------------- alias scene_base_update_basic_cxj_inpex update_basic def update_basic scene_base_update_basic_cxj_inpex if CXJ::INPEX::ENABLE_CUSTOM_POINTER Mouse.update if CXJ::INPEX::INCLUDE_CORE CXJ::INPEX::Mouse.update if !CXJ::INPEX::INCLUDE_CORE end end end