rbnput-darwin-minimal 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/rbnput/darwin_ffi.rb +68 -0
- data/lib/rbnput/darwin_listener.rb +91 -0
- data/lib/rbnput/key_code.rb +45 -0
- data/lib/rbnput/key_code_const.rb +128 -0
- data/lib/rbnput/simple_mutex_thread.rb +44 -0
- data/lib/rbnput/version.rb +6 -0
- data/lib/rbnput-darwin-minimal.rb +26 -0
- metadata +59 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 594358ceb0f0f0e7221573889dc49812811c4650bacfc7ac83632f9a34c786ea
|
|
4
|
+
data.tar.gz: a796a9ad610243fdfe74a3f35ccadf1cb27700bd7c38c72219c5f50767922d4f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a8927a2cbc7c1253c5cf79c68393c2008824688147a8086ba8fb41c46e53ba01b6efb682c2b33c02b4d420eec584e3d47470dbee78762b2c7f5b9cdcdbd4a80e
|
|
7
|
+
data.tar.gz: fafd61a4756920e3c8c32012e9e6717fb8af19c6459862aec7b413bc2949081dc50e0dfd44a3a16e0b4904a275efe0a9f973fbe408c7b53f5f5a13434eac89ce
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ffi'
|
|
4
|
+
|
|
5
|
+
module Rbnput::DarwinFFI
|
|
6
|
+
extend FFI::Library
|
|
7
|
+
ffi_lib ['/System/Library/Frameworks/ApplicationServices.framework/ApplicationServices',
|
|
8
|
+
'/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation']
|
|
9
|
+
|
|
10
|
+
# CoreFoundation types
|
|
11
|
+
typedef :pointer, :CFMachPortRef
|
|
12
|
+
typedef :pointer, :CFRunLoopSourceRef
|
|
13
|
+
typedef :pointer, :CFRunLoopRef
|
|
14
|
+
typedef :pointer, :CFStringRef
|
|
15
|
+
typedef :pointer, :CGEventTapProxy
|
|
16
|
+
typedef :pointer, :CGEventRef
|
|
17
|
+
|
|
18
|
+
# Constants
|
|
19
|
+
KCGSessionEventTap = 0
|
|
20
|
+
KCGHeadInsertEventTap = 0
|
|
21
|
+
KCGEventTapOptionDefault = 0x00000000
|
|
22
|
+
KCGEventTapOptionListenOnly = 0x00000001
|
|
23
|
+
|
|
24
|
+
KCFRunLoopRunFinished = 1
|
|
25
|
+
KCFRunLoopRunStopped = 2
|
|
26
|
+
KCFRunLoopRunTimedOut = 3
|
|
27
|
+
KCFRunLoopRunHandledSource = 4
|
|
28
|
+
|
|
29
|
+
KCGEventSourceUnixProcessID = 1
|
|
30
|
+
KCGKeyboardEventKeycode = 9
|
|
31
|
+
|
|
32
|
+
KCGScrollWheelEventDeltaAxis1 = 11 # Y
|
|
33
|
+
KCGScrollWheelEventDeltaAxis2 = 12 # X
|
|
34
|
+
|
|
35
|
+
KCGEventKeyDown = 10
|
|
36
|
+
KCGEventKeyUp = 11
|
|
37
|
+
KCGEventFlagsChanged = 12
|
|
38
|
+
|
|
39
|
+
# We need to get the kCFRunLoopDefaultMode constant value
|
|
40
|
+
# It's a CFStringRef. For simplicity in FFI, we can often pass NULL (0) for default mode in some APIs,
|
|
41
|
+
# but CFRunLoopAddSource requires a mode.
|
|
42
|
+
# A common workaround is to look it up or define it if we know the symbol name.
|
|
43
|
+
# However, getting the actual pointer value of a constant exported by a dylib in FFI can be tricky.
|
|
44
|
+
# We'll try to attach it.
|
|
45
|
+
attach_variable :kCFRunLoopDefaultMode, :kCFRunLoopDefaultMode, :pointer
|
|
46
|
+
|
|
47
|
+
# CGEventTapCallback
|
|
48
|
+
callback :CGEventTapCallback, [:pointer, :int, :pointer, :pointer], :pointer
|
|
49
|
+
|
|
50
|
+
# Functions
|
|
51
|
+
attach_function :CGEventTapCreate, [:int, :int, :int, :uint64, :CGEventTapCallback, :pointer], :CFMachPortRef
|
|
52
|
+
attach_function :CGEventTapEnable, [:CFMachPortRef, :bool], :void
|
|
53
|
+
attach_function :CFMachPortCreateRunLoopSource, [:pointer, :CFMachPortRef, :long], :CFRunLoopSourceRef
|
|
54
|
+
attach_function :CFRunLoopGetCurrent, [], :CFRunLoopRef
|
|
55
|
+
attach_function :CFRunLoopAddSource, [:CFRunLoopRef, :CFRunLoopSourceRef, :pointer], :void
|
|
56
|
+
attach_function :CFRunLoopRunInMode, [:pointer, :double, :bool], :int
|
|
57
|
+
attach_function :CFRunLoopStop, [:CFRunLoopRef], :void
|
|
58
|
+
attach_function :CFRelease, [:pointer], :void
|
|
59
|
+
attach_function :AXIsProcessTrusted, [], :bool
|
|
60
|
+
attach_function :CGEventGetIntegerValueField, [:pointer, :int], :int64
|
|
61
|
+
attach_function :CGEventGetType, [:pointer], :int
|
|
62
|
+
attach_function :CGEventGetFlags, [:pointer], :uint64
|
|
63
|
+
attach_function :CGEventCreateKeyboardEvent, [:pointer, :uint16, :bool], :pointer
|
|
64
|
+
attach_function :CGEventPost, [:int, :pointer], :void
|
|
65
|
+
attach_function :CGEventSourceCreate, [:int], :pointer
|
|
66
|
+
attach_function :CFRelease, [:pointer], :void
|
|
67
|
+
attach_function :CGEventSetFlags, [:pointer, :uint64], :void
|
|
68
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'set'
|
|
4
|
+
require_relative './key_code'
|
|
5
|
+
require_relative './simple_mutex_thread'
|
|
6
|
+
require_relative './darwin_ffi'
|
|
7
|
+
|
|
8
|
+
module Rbnput
|
|
9
|
+
# Base listener for keyboard events
|
|
10
|
+
class DarwinListener < Rbnput::SimpleMutexThread
|
|
11
|
+
def initialize(on_press: nil, on_release: nil, **kwargs)
|
|
12
|
+
super(*kwargs)
|
|
13
|
+
@on_press = on_press
|
|
14
|
+
@on_release = on_release
|
|
15
|
+
|
|
16
|
+
@loop = nil
|
|
17
|
+
@tap = nil
|
|
18
|
+
@callback_proc = nil # Keep reference to prevent GC
|
|
19
|
+
end
|
|
20
|
+
attr_reader :on_press, :on_release
|
|
21
|
+
|
|
22
|
+
def on_press(&proc)
|
|
23
|
+
@on_press = proc
|
|
24
|
+
end
|
|
25
|
+
def on_release(&proc)
|
|
26
|
+
@on_press = proc
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def _run
|
|
30
|
+
unless Rbnput::DarwinFFI.AXIsProcessTrusted()
|
|
31
|
+
@log.warn("Process is not trusted! Input monitoring will not work until added to accessibility clients.")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Create the callback
|
|
35
|
+
@callback_proc = FFI::Function.new(:pointer, [:pointer, :int, :pointer, :pointer]) do |proxy, type, event, refcon|
|
|
36
|
+
key_code = DarwinFFI
|
|
37
|
+
.CGEventGetIntegerValueField(event, Rbnput::DarwinFFI::KCGKeyboardEventKeycode)
|
|
38
|
+
.then { |vk| KeyCode.from_vk(vk) }
|
|
39
|
+
|
|
40
|
+
case type
|
|
41
|
+
when Rbnput::DarwinFFI::KCGEventKeyDown; @on_press&.call(key_code)
|
|
42
|
+
when Rbnput::DarwinFFI::KCGEventKeyUp; @on_release&.call(key_code)
|
|
43
|
+
when Rbnput::DarwinFFI::KCGEventFlagsChanged; @on_press&.call(key_code)
|
|
44
|
+
end
|
|
45
|
+
event
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
@tap = Rbnput::DarwinFFI.CGEventTapCreate(
|
|
49
|
+
Rbnput::DarwinFFI::KCGSessionEventTap,
|
|
50
|
+
Rbnput::DarwinFFI::KCGHeadInsertEventTap,
|
|
51
|
+
Rbnput::DarwinFFI::KCGEventTapOptionDefault,
|
|
52
|
+
(1 << Rbnput::DarwinFFI::KCGEventKeyDown) | (1 << Rbnput::DarwinFFI::KCGEventKeyUp) | (1 << Rbnput::DarwinFFI::KCGEventFlagsChanged),
|
|
53
|
+
@callback_proc,
|
|
54
|
+
nil
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
if @tap.null?
|
|
58
|
+
@log.error("Failed to create event tap")
|
|
59
|
+
return
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Create run loop source
|
|
63
|
+
source = Rbnput::DarwinFFI.CFMachPortCreateRunLoopSource(nil, @tap, 0)
|
|
64
|
+
|
|
65
|
+
# Add to current run loop
|
|
66
|
+
@loop = Rbnput::DarwinFFI.CFRunLoopGetCurrent()
|
|
67
|
+
Rbnput::DarwinFFI.CFRunLoopAddSource(@loop, source, Rbnput::DarwinFFI.kCFRunLoopDefaultMode)
|
|
68
|
+
|
|
69
|
+
# Enable tap
|
|
70
|
+
Rbnput::DarwinFFI.CGEventTapEnable(@tap, true)
|
|
71
|
+
|
|
72
|
+
# Run loop
|
|
73
|
+
while @running
|
|
74
|
+
_result = Rbnput::DarwinFFI.CFRunLoopRunInMode(Rbnput::DarwinFFI.kCFRunLoopDefaultMode, 0.1, false)
|
|
75
|
+
|
|
76
|
+
# 0.1 second timeout allows us to check @running flag
|
|
77
|
+
end
|
|
78
|
+
ensure
|
|
79
|
+
Rbnput::DarwinFFI.CFRelease(@tap) if @tap && !@tap.null?
|
|
80
|
+
Rbnput::DarwinFFI.CFRelease(source) if source && !source.null?
|
|
81
|
+
@tap = nil
|
|
82
|
+
@loop = nil
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def stop
|
|
86
|
+
super
|
|
87
|
+
Rbnput::DarwinFFI.CFRunLoopStop(@loop) if @loop && !@loop.null?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require_relative "./key_code_const"
|
|
2
|
+
|
|
3
|
+
class Rbnput::KeyCode
|
|
4
|
+
attr_reader :vk, :is_media
|
|
5
|
+
|
|
6
|
+
def initialize(vk: nil, is_media: false)
|
|
7
|
+
@vk = vk
|
|
8
|
+
@is_media = is_media
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_s
|
|
12
|
+
[
|
|
13
|
+
@vk.nil? ? "" : "vk=#{@vk}",
|
|
14
|
+
@is_media ? "media" : "",
|
|
15
|
+
]
|
|
16
|
+
.reject(&:empty?)
|
|
17
|
+
.join(", ")
|
|
18
|
+
.then { "KeyCode(#{_1}, #{key})" }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def key
|
|
22
|
+
KEY_CODE_HEX_TO_NAME[@vk] || "UNKNOW"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def ==(other)
|
|
26
|
+
return false unless other.is_a?(KeyCode)
|
|
27
|
+
@vk == other.vk && @is_media == other.is_media
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
alias eql? ==
|
|
31
|
+
|
|
32
|
+
def hash
|
|
33
|
+
[@vk, @is_media].hash
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.from_vk(vk, **kwargs)
|
|
37
|
+
new(vk: vk, is_media: false, **kwargs)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.from_media(vk, **kwargs)
|
|
41
|
+
new(vk: vk, is_media: true, **kwargs)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
KEY_CODE_NAME_TO_HEX = {
|
|
2
|
+
:kVK_ANSI_A => 0x00,
|
|
3
|
+
:kVK_ANSI_S => 0x01,
|
|
4
|
+
:kVK_ANSI_D => 0x02,
|
|
5
|
+
:kVK_ANSI_F => 0x03,
|
|
6
|
+
:kVK_ANSI_H => 0x04,
|
|
7
|
+
:kVK_ANSI_G => 0x05,
|
|
8
|
+
:kVK_ANSI_Z => 0x06,
|
|
9
|
+
:kVK_ANSI_X => 0x07,
|
|
10
|
+
:kVK_ANSI_C => 0x08,
|
|
11
|
+
:kVK_ANSI_V => 0x09,
|
|
12
|
+
:kVK_ANSI_B => 0x0B,
|
|
13
|
+
:kVK_ANSI_Q => 0x0C,
|
|
14
|
+
:kVK_ANSI_W => 0x0D,
|
|
15
|
+
:kVK_ANSI_E => 0x0E,
|
|
16
|
+
:kVK_ANSI_R => 0x0F,
|
|
17
|
+
:kVK_ANSI_Y => 0x10,
|
|
18
|
+
:kVK_ANSI_T => 0x11,
|
|
19
|
+
:kVK_ANSI_1 => 0x12,
|
|
20
|
+
:kVK_ANSI_2 => 0x13,
|
|
21
|
+
:kVK_ANSI_3 => 0x14,
|
|
22
|
+
:kVK_ANSI_4 => 0x15,
|
|
23
|
+
:kVK_ANSI_6 => 0x16,
|
|
24
|
+
:kVK_ANSI_5 => 0x17,
|
|
25
|
+
:kVK_ANSI_Equal => 0x18,
|
|
26
|
+
:kVK_ANSI_9 => 0x19,
|
|
27
|
+
:kVK_ANSI_7 => 0x1A,
|
|
28
|
+
:kVK_ANSI_Minus => 0x1B,
|
|
29
|
+
:kVK_ANSI_8 => 0x1C,
|
|
30
|
+
:kVK_ANSI_0 => 0x1D,
|
|
31
|
+
:kVK_ANSI_RightBracket => 0x1E,
|
|
32
|
+
:kVK_ANSI_O => 0x1F,
|
|
33
|
+
:kVK_ANSI_U => 0x20,
|
|
34
|
+
:kVK_ANSI_LeftBracket => 0x21,
|
|
35
|
+
:kVK_ANSI_I => 0x22,
|
|
36
|
+
:kVK_ANSI_P => 0x23,
|
|
37
|
+
:kVK_ANSI_L => 0x25,
|
|
38
|
+
:kVK_ANSI_J => 0x26,
|
|
39
|
+
:kVK_ANSI_Quote => 0x27,
|
|
40
|
+
:kVK_ANSI_K => 0x28,
|
|
41
|
+
:kVK_ANSI_Semicolon => 0x29,
|
|
42
|
+
:kVK_ANSI_Backslash => 0x2A,
|
|
43
|
+
:kVK_ANSI_Comma => 0x2B,
|
|
44
|
+
:kVK_ANSI_Slash => 0x2C,
|
|
45
|
+
:kVK_ANSI_N => 0x2D,
|
|
46
|
+
:kVK_ANSI_M => 0x2E,
|
|
47
|
+
:kVK_ANSI_Period => 0x2F,
|
|
48
|
+
:kVK_ANSI_Grave => 0x32,
|
|
49
|
+
:kVK_ANSI_KeypadDecimal => 0x41,
|
|
50
|
+
:kVK_ANSI_KeypadMultiply => 0x43,
|
|
51
|
+
:kVK_ANSI_KeypadPlus => 0x45,
|
|
52
|
+
:kVK_ANSI_KeypadClear => 0x47,
|
|
53
|
+
:kVK_ANSI_KeypadDivide => 0x4B,
|
|
54
|
+
:kVK_ANSI_KeypadEnter => 0x4C,
|
|
55
|
+
:kVK_ANSI_KeypadMinus => 0x4E,
|
|
56
|
+
:kVK_ANSI_KeypadEquals => 0x51,
|
|
57
|
+
:kVK_ANSI_Keypad0 => 0x52,
|
|
58
|
+
:kVK_ANSI_Keypad1 => 0x53,
|
|
59
|
+
:kVK_ANSI_Keypad2 => 0x54,
|
|
60
|
+
:kVK_ANSI_Keypad3 => 0x55,
|
|
61
|
+
:kVK_ANSI_Keypad4 => 0x56,
|
|
62
|
+
:kVK_ANSI_Keypad5 => 0x57,
|
|
63
|
+
:kVK_ANSI_Keypad6 => 0x58,
|
|
64
|
+
:kVK_ANSI_Keypad7 => 0x59,
|
|
65
|
+
:kVK_ANSI_Keypad8 => 0x5B,
|
|
66
|
+
:kVK_ANSI_Keypad9 => 0x5C,
|
|
67
|
+
:kVK_F1 => 0x7A,
|
|
68
|
+
:kVK_F2 => 0x78,
|
|
69
|
+
:kVK_F3 => 0x63,
|
|
70
|
+
:kVK_F4 => 0x76,
|
|
71
|
+
:kVK_F5 => 0x60,
|
|
72
|
+
:kVK_F6 => 0x61,
|
|
73
|
+
:kVK_F7 => 0x62,
|
|
74
|
+
:kVK_F8 => 0x64,
|
|
75
|
+
:kVK_F9 => 0x65,
|
|
76
|
+
:kVK_F10 => 0x6D,
|
|
77
|
+
:kVK_F11 => 0x67,
|
|
78
|
+
:kVK_F12 => 0x6F,
|
|
79
|
+
:kVK_F13 => 0x69,
|
|
80
|
+
:kVK_F14 => 0x6B,
|
|
81
|
+
:kVK_F15 => 0x71,
|
|
82
|
+
:kVK_F16 => 0x6A,
|
|
83
|
+
:kVK_F17 => 0x40,
|
|
84
|
+
:kVK_F18 => 0x4F,
|
|
85
|
+
:kVK_F19 => 0x50,
|
|
86
|
+
:kVK_F20 => 0x5A,
|
|
87
|
+
:kVK_Space => 0x31,
|
|
88
|
+
:kVK_Return => 0x24,
|
|
89
|
+
:kVK_Tab => 0x30,
|
|
90
|
+
:kVK_Delete => 0x33,
|
|
91
|
+
:kVK_Escape => 0x35,
|
|
92
|
+
:kVK_LeftCommand => 0x37,
|
|
93
|
+
:kVK_LeftShift => 0x38,
|
|
94
|
+
:kVK_CapsLock => 0x39,
|
|
95
|
+
:kVK_LeftOption => 0x3A,
|
|
96
|
+
:kVK_LeftControl => 0x3B,
|
|
97
|
+
:kVK_RightShift => 0x3C,
|
|
98
|
+
:kVK_RightOption => 0x3D,
|
|
99
|
+
:kVK_RightControl => 0x3E,
|
|
100
|
+
:kVK_RightCommand => 0x36, # ใช่ ตัวนี้! Apple ไม่บอก แต่ใช้อันนี้
|
|
101
|
+
:kVK_Function => 0x3F,
|
|
102
|
+
:kVK_Home => 0x73,
|
|
103
|
+
:kVK_PageUp => 0x74,
|
|
104
|
+
:kVK_ForwardDelete => 0x75,
|
|
105
|
+
:kVK_End => 0x77,
|
|
106
|
+
:kVK_PageDown => 0x79,
|
|
107
|
+
:kVK_LeftArrow => 0x7B,
|
|
108
|
+
:kVK_RightArrow => 0x7C,
|
|
109
|
+
:kVK_DownArrow => 0x7D,
|
|
110
|
+
:kVK_UpArrow => 0x7E
|
|
111
|
+
|
|
112
|
+
# Not Implement Yet
|
|
113
|
+
# • NSEvent.otherEventWithType(NSSystemDefined)
|
|
114
|
+
# • subtype = 8
|
|
115
|
+
# • data1 = (0xA << 16) | (keycode << 8)
|
|
116
|
+
# NX_KEYTYPE_SOUND_UP = 0
|
|
117
|
+
# NX_KEYTYPE_SOUND_DOWN = 1
|
|
118
|
+
# NX_KEYTYPE_MUTE = 7
|
|
119
|
+
# NX_KEYTYPE_PLAY = 16
|
|
120
|
+
# NX_KEYTYPE_NEXT = 17
|
|
121
|
+
# NX_KEYTYPE_PREVIOUS = 18
|
|
122
|
+
# NX_KEYTYPE_ILLUMINATION_UP = 21
|
|
123
|
+
# NX_KEYTYPE_ILLUMINATION_DOWN = 20
|
|
124
|
+
# NX_KEYTYPE_FAST = 19
|
|
125
|
+
# NX_KEYTYPE_REWIND = 20
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
KEY_CODE_HEX_TO_NAME = KEY_CODE_NAME_TO_HEX.invert
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'thread'
|
|
4
|
+
|
|
5
|
+
class Rbnput::SimpleMutexThread
|
|
6
|
+
|
|
7
|
+
protected
|
|
8
|
+
# Platform-specific run implementation
|
|
9
|
+
# Must be implemented by subclasses
|
|
10
|
+
def _run; raise NotImplementedError, "Subclasses must implement _run" end
|
|
11
|
+
|
|
12
|
+
public
|
|
13
|
+
attr_reader :running
|
|
14
|
+
def initialize
|
|
15
|
+
@running = false
|
|
16
|
+
@thread = nil
|
|
17
|
+
@mutex = Mutex.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Start the listener in a separate thread
|
|
21
|
+
def start
|
|
22
|
+
@mutex.synchronize do
|
|
23
|
+
return if @running
|
|
24
|
+
@running = true
|
|
25
|
+
@thread = Thread.new do
|
|
26
|
+
begin; _run
|
|
27
|
+
ensure; @running = false end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Stop the listener
|
|
34
|
+
def stop
|
|
35
|
+
@mutex.synchronize do; @running = false end
|
|
36
|
+
@thread&.join(5) # Wait up to 5 seconds
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def join; @thread&.join end
|
|
41
|
+
def alive?; @running && @thread&.alive? end
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Rbnput - Ruby Input Library
|
|
4
|
+
# Copyright (C) 2025
|
|
5
|
+
#
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify it under
|
|
7
|
+
# the terms of the GNU Lesser General Public License as published by the Free
|
|
8
|
+
# Software Foundation, either version 3 of the License, or (at your option) any
|
|
9
|
+
# later version.
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
13
|
+
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
14
|
+
# details.
|
|
15
|
+
|
|
16
|
+
require_relative "rbnput/version"
|
|
17
|
+
require_relative "rbnput/darwin_listener"
|
|
18
|
+
# require_relative "rbnput/mouse"
|
|
19
|
+
|
|
20
|
+
# The main Rbnput module
|
|
21
|
+
#
|
|
22
|
+
# This module imports keyboard and mouse submodules for controlling
|
|
23
|
+
# and monitoring input devices.
|
|
24
|
+
module Rbnput
|
|
25
|
+
Listener = ::Rbnput::DarwinListener
|
|
26
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rbnput-darwin-minimal
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Krist Ponpairin
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: ffi
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.15'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.15'
|
|
26
|
+
description: A Ruby library for keyboard monitoring in mac
|
|
27
|
+
email:
|
|
28
|
+
- krist7599555@gmail.com
|
|
29
|
+
executables: []
|
|
30
|
+
extensions: []
|
|
31
|
+
extra_rdoc_files: []
|
|
32
|
+
files:
|
|
33
|
+
- lib/rbnput-darwin-minimal.rb
|
|
34
|
+
- lib/rbnput/darwin_ffi.rb
|
|
35
|
+
- lib/rbnput/darwin_listener.rb
|
|
36
|
+
- lib/rbnput/key_code.rb
|
|
37
|
+
- lib/rbnput/key_code_const.rb
|
|
38
|
+
- lib/rbnput/simple_mutex_thread.rb
|
|
39
|
+
- lib/rbnput/version.rb
|
|
40
|
+
licenses: []
|
|
41
|
+
metadata: {}
|
|
42
|
+
rdoc_options: []
|
|
43
|
+
require_paths:
|
|
44
|
+
- lib
|
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: '0'
|
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
requirements: []
|
|
56
|
+
rubygems_version: 3.7.2
|
|
57
|
+
specification_version: 4
|
|
58
|
+
summary: Ruby Input library (rbnput)
|
|
59
|
+
test_files: []
|