- #============================================================================== 
- # ■ [Keyboard Indie] 全键盘处理核心 v1.1 by SailCat 
- #------------------------------------------------------------------------------ 
- #   方法:本脚本插入Main之前使用 
- #   依赖:无 
- #   版本:v1.1 (Build 220224) 
- #   效果: 
- #     1. 全键盘按键响应 
- #     2. 注入Input模块的update处理 
- #     3. Lock键、Shift/Ctrl/Alt/Win键状态的响应 
- #     4. 获得输入的字符 
- #   配置:重复延迟和重复间隔速率 
- #   冲突:其他类似脚本 
- #   说明: 
- #     1. 调用全键盘方法为Keyboard.press?(键名常量、符号或字符)。 
- #     2. 上述press?也可替换为trigger?或repeat?,含义与Input中的同名方法相同。 
- #     3. 其他检测包括对于Lock键的状态,Shift/Ctrl/Alt/Win的状态检测等。 
- #     4. 使用Keyboard.type_char可以获得打字键入的字符。 
- #============================================================================== 
- #============================================================================== 
- # ■ SailCat's 插件公用 
- #============================================================================== 
- module SailCat 
-   #-------------------------------------------------------------------------- 
-   # ● 脚本配置区 
-   #-------------------------------------------------------------------------- 
-   module Keyboard_Config 
-     REPEAT_DELAY = 8            # 首次重复前的延迟值(帧) 
-     REPEAT_SPEED = 4            # 每次重复按键的间隔(帧),越大越慢 
-     #-------------------------------------------------------------------------- 
-     # ● 配置检查,请勿更改 
-     #-------------------------------------------------------------------------- 
-     raise "重复按键的间隔不能低于1帧" unless REPEAT_SPEED > 0 
-   end 
- end 
-   
- #============================================================================== 
- # ■ 全键盘处理核心 
- #============================================================================== 
- module Keyboard 
-   include SailCat::Keyboard_Config 
-   #-------------------------------------------------------------------------- 
-   # ● 常量 
-   #-------------------------------------------------------------------------- 
-   NONE = 0 
-   L_BUTTON, R_BUTTON, CANCEL, M_BUTTON, X_BUTTON1, X_BUTTON2 = *1..6 
-   BACKSPACE, TAB, LINE_FEED, V_TAB, CLEAR, ENTER = *8..13 
-   SHIFT_KEY, CONTROL_KEY, ALT_KEY, PAUSE_KEY = *16..19 
-   CAPS_LOCK, KANA_MODE, JUNJA_MODE, DUMMY, FINAL_MODE, KANJI_MODE = *20..25 
-   ESCAPE, IME_CONVERT, IME_NONCONVERT, IME_ACCEPT, IME_MODECHANGE = *27..31 
-   SPACE, PAGEUP, PAGEDOWN, ENDKEY, HOME, LEFT, UP, RIGHT, DOWN = *32..40 
-   SELECT, PRINT, EXECUTE, PRINTSCREEN, INSERT, DELETE, HELP = *41..47 
-   D0, D1, D2, D3, D4, D5, D6, D7, D8, D9 = *48..57 
-   A, B, C, D, E, F, G, H, I, J, K, L, M = *65..77 
-   N, O, P, Q, R, S, T, U, V, W, X, Y, Z = *78..90 
-   LWIN, RWIN, APPS, SLEEP = 91, 92, 93, 95 
-   NUM0, NUM1, NUM2, NUM3, NUM4, NUM5, NUM6, NUM7, NUM8, NUM9 = *96..105 
-   MULTIPLY, ADD, SEPARATOR, SUBTRACT, DECIMAL, DIVIDE = *106..111 
-   F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12 = *112..123 
-   F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24 = *124..135 
-   NUM_LOCK, SCROLL_LOCK = 144, 145 
-   L_SHIFT, R_SHIFT, L_CTRL, R_CTRL, L_ALT, R_ALT = *160..165 
-   B_BACK, B_FORWARD, B_REFRESH, B_STOP, B_SEARCH, B_FAVOR, B_HOME = *166..172 
-   VOL_MUTE, VOL_DOWN, VOL_UP = *173..175 
-   MEDIA_NEXT, MEDIA_PREVIOUS, MEDIA_STOP, MEDIA_PLAYPAUSE = *176..179 
-   LAUNCH_MAIL, SELECT_MEDIA, LAUNCH_APP1, LAUNCH_APP2 = *180..183 
-   SEMICOLON, PLUS, COMMA, MINUS, PERIOD, QUESTION, TILDE = *186..192 
-   L_BRACE, PIPE, R_BRACE, QUOTE, OEM8 = *219..223 
-   BACKSLASH, PROCESS_KEY, PACKET = 226, 229, 231 
-   ATTN, CRSEL, EXSEL, ERASE_EOF, PLAY, ZOOM, NONAME, PA1, OEM_CLEAR = *246..254 
-   ANY_BUTTON = [1, 2, 4, 5, 6] 
-   ANY_KEY = [8..13, 27, 32..57, 65..90, 96..135, 186..192, 219..223].map do |x| 
-     x.to_a 
-   end.flatten 
-   #-------------------------------------------------------------------------- 
-   # ● API 
-   #-------------------------------------------------------------------------- 
-   GetAsyncKeyState = Win32API.new("user32", "GetAsyncKeyState", "i", "i") 
-   GetKeyState = Win32API.new("user32", "GetKeyState", "i", "i") 
-   #-------------------------------------------------------------------------- 
-   # ● 用于检测重复按键的标记器 
-   #-------------------------------------------------------------------------- 
-   Flags = {} 
-   #-------------------------------------------------------------------------- 
-   # ● 更新键盘输入,该方法每帧调用1次 
-   #-------------------------------------------------------------------------- 
-   def self.update 
-     @keychar = nil 
-     Flags.each_key do |k| 
-       GetAsyncKeyState.call(k) & 32768 != 0 ? Flags[k] += 1 : Flags.delete(k) 
-     end 
-   end 
-   #-------------------------------------------------------------------------- 
-   # ● 判断对应的键是否现在被按下 
-   #-------------------------------------------------------------------------- 
-   def self.press?(key) 
-     key = get_key(key) unless key.is_a?(Numeric) or key.is_a?(Array) 
-     return key.any?{|k| press?(k)} if key.is_a?(Array) 
-     GetAsyncKeyState.call(key) & 32768 != 0 ? (Flags[key] ||= 0; true) : false 
-   end 
-   #-------------------------------------------------------------------------- 
-   # ● 判断对应的键是否重新被按下 
-   #-------------------------------------------------------------------------- 
-   def self.trigger?(key) 
-     key = get_key(key) unless key.is_a?(Numeric) or key.is_a?(Array) 
-     return key.any?{|k| trigger?(k)} if key.is_a?(Array) 
-     Flags[key] ? Flags[key] == 0 : press?(key) 
-   end 
-   #-------------------------------------------------------------------------- 
-   # ● 判断对应的键是否重复被按下 
-   #-------------------------------------------------------------------------- 
-   def self.repeat?(key) 
-     key = get_key(key) unless key.is_a?(Numeric) or key.is_a?(Array) 
-     return key.any?{|k| repeat?(k)} if key.is_a?(Array) 
-     Flags[key] ? (Flags[key] == 0 or Flags[key] >= REPEAT_DELAY and  
-     (Flags[key] - REPEAT_DELAY) % REPEAT_SPEED == 0) : press?(key) 
-   end 
-   #-------------------------------------------------------------------------- 
-   # ● 键盘状态判断 
-   #-------------------------------------------------------------------------- 
-   def self.lock?(key);    GetKeyState.call(key) & 1 == 1;           end 
-   def self.caps_lock?;    lock?(CAPS_LOCK);                         end 
-   def self.num_lock?;     lock?(NUM_LOCK);                          end 
-   def self.scroll_lock?;  lock?(SCROLL_LOCK);                       end 
-   #-------------------------------------------------------------------------- 
-   # ● 修饰键判断 
-   #-------------------------------------------------------------------------- 
-   def self.shift?;        press?([SHIFT_KEY, L_SHIFT, R_SHIFT]);    end 
-   def self.ctrl?;         press?([CONTROL_KEY, L_CTRL, R_CTRL]);    end 
-   def self.alt?;          press?([ALT_KEY, L_ALT, R_ALT]);          end 
-   def self.win?;          press?([L_WIN, R_WIN]);                   end 
-   #-------------------------------------------------------------------------- 
-   # ● 当前按下的键名 
-   #-------------------------------------------------------------------------- 
-   def self.key_code 
-     a = ANY_KEY.select{|key| repeat?(key)} 
-     a.empty? ? 0 : a[0] 
-   end 
-   #-------------------------------------------------------------------------- 
-   # ● 当前输入的字符 
-   #-------------------------------------------------------------------------- 
-   def self.type_char 
-     @keychar ||= key2char(key_code, shift?, caps_lock?, num_lock?) 
-   end 
-   #-------------------------------------------------------------------------- 
-   # ● 打字中判定 
-   #-------------------------------------------------------------------------- 
-   def self.typing? 
-     not type_char.empty? 
-   end 
-   #-------------------------------------------------------------------------- 
-   # ● 根据字符或符号取得键名 
-   #-------------------------------------------------------------------------- 
-   def self.get_key(key) 
-     if key.is_a?(Symbol) 
-       const_get(key) rescue NONE 
-     elsif key.is_a?(String) 
-       char2key(key) 
-     end 
-   end 
-   #-------------------------------------------------------------------------- 
-   # ● 将按键转化为字符 
-   #-------------------------------------------------------------------------- 
-   def self.key2char(code, shift = false, caps = false, num = true) 
-     case code 
-     when NONE 
-       "" 
-     when BACKSPACE..ENTER, ESCAPE, SPACE 
-       code.chr 
-     when D0..D9 
-       shift ? ")!@#\$%^&*("[code - D0].chr : code.chr 
-     when A..Z 
-       shift ^ caps ? code.chr : (code + 32).chr 
-     when NUM0..NUM9 
-       num ? (code - 48).chr : "" 
-     when MULTIPLY..DIVIDE 
-       (num || code != DECIMAL) ? "*+,-./"[code - 106].chr : "" 
-     when SEMICOLON..TILDE 
-       ";:=+,<-_.>/?`~"[(code - SEMICOLON << 1) + (shift ? 1 : 0)].chr 
-     when L_BRACE..QUOTE 
-       "[{\\|]}\'\""[(code - L_BRACE << 1) + (shift ? 1 : 0)].chr 
-     else 
-       "" 
-     end 
-   end 
-   #-------------------------------------------------------------------------- 
-   # ● 将字符转化为按键 
-   #-------------------------------------------------------------------------- 
-   def self.char2key(char) 
-     return NONE if char.empty? 
-     case char[0] 
-     when 8..13, 27, 32, 48..57, 65..90 
-       char[0] 
-     when 97..122 
-       char[0] - 32 
-     else 
-       pindex = ")!@#\$%^&*(".index(char[0]) 
-       return D0 + pindex if pindex 
-       pindex = ";:=+,<-_.>/?`~".index(char[0]) 
-       return SEMICOLON + (pindex >> 1) if pindex 
-       pindex = "[{\\|]}\'\"".index(char[0]) 
-       return L_BRACE + (pindex >> 1) if pindex 
-       NONE 
-     end 
-   end   
- end 
-   
- #============================================================================== 
- # ■ Input 模块的注入 
- #============================================================================== 
- module Input 
-   unless method_defined?(:sailcat_kb_update) 
-     alias sailcat_kb_update update 
-     def update 
-       sailcat_kb_update 
-       Keyboard.update 
-     end 
-   end 
- end