rbnput-darwin-minimal 0.2.0 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3317cf0ccce42301ac2051688baf804f1f17f56bdf71b2af9c6a8e27b90d4869
4
- data.tar.gz: c11a98352c3eff90c3618188ee865501649b48a6fb1fa23342871e9e2fe35e0e
3
+ metadata.gz: bde651d183da7dc9b3e17dcf9a4789fb1f2e16ca089909f8440b87056a23baf7
4
+ data.tar.gz: eb0416ba45e6545674ff3cbf12172db87feee358fddd3eeedfa96056869e6f6a
5
5
  SHA512:
6
- metadata.gz: 5a019ea1d2117c1794eacfd1a4583b319bde5cd0ee030d6c208c66fa6ae7a8d7c1c8e9b8904108e6590562672f3e4e0da3893e34011750d39e20b3b2baabc9aa
7
- data.tar.gz: 887fe4b1c904f54da8b42d0a28556c5933c06a839cf79665e33a3d4050f6bb4b94bbca18ed3dbc78ba8bf978d39697e3b39564cf1e489a7c26449a7cdc2aaef4
6
+ metadata.gz: 9ae0c01ddfcc21e87a38e3d5977ff54a7233ff73bbf9544bb1903534ca6cc26388abbc9c2871a34e00b271aec767f58e00d3191445e5abb6f3b984d0a55c92f0
7
+ data.tar.gz: 3f8b61f1abdeae98b6ba07ce6f1126ea6142df78fe446d8a5933dab1b57384bb23e5ca68adcb2d9b654307a851ba67b4ded64b2eb105f7612ebc6e3643b0eb09
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # 🎹 rbnput-darwin-minimal 🍎
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/rbnput-darwin-minimal.svg)](https://badge.fury.io/rb/rbnput-darwin-minimal)
4
+ [![GitHub](https://img.shields.io/badge/github-repo-blue)](https://github.com/krist7599555/rbnput-darwin-minimal)
5
+
3
6
  ไลบรารี Ruby ขนาดเล็กสำหรับตรวจจับการกดแป้นพิมพ์บนระบบ macOS โดยใช้ FFI เชื่อมต่อกับ system library ของ Darwin โดยตรง
4
7
 
5
8
  ## ✨ คุณสมบัติ
@@ -2,67 +2,151 @@
2
2
 
3
3
  require 'ffi'
4
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
5
+ module Rbnput
6
+ # FFI bindings for macOS ApplicationServices and CoreFoundation.
7
+ # Provides low-level access to Quartz Event Services.
8
+ #
9
+ # @api private
10
+ module DarwinFFI
11
+ extend FFI::Library
12
+ ffi_lib ['/System/Library/Frameworks/ApplicationServices.framework/ApplicationServices',
13
+ '/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation']
14
+
15
+ # CoreFoundation types
16
+ typedef :pointer, :CFMachPortRef
17
+ typedef :pointer, :CFRunLoopSourceRef
18
+ typedef :pointer, :CFRunLoopRef
19
+ typedef :pointer, :CFStringRef
20
+ typedef :pointer, :CGEventTapProxy
21
+ typedef :pointer, :CGEventRef
22
+
23
+ # Constants
24
+ KCGSessionEventTap = 0
25
+ KCGHeadInsertEventTap = 0
26
+ KCGEventTapOptionDefault = 0x00000000
27
+ KCGEventTapOptionListenOnly = 0x00000001
28
+
29
+ KCFRunLoopRunFinished = 1
30
+ KCFRunLoopRunStopped = 2
31
+ KCFRunLoopRunTimedOut = 3
32
+ KCFRunLoopRunHandledSource = 4
33
+
34
+ KCGEventSourceUnixProcessID = 1
35
+ KCGKeyboardEventKeycode = 9
36
+
37
+ KCGScrollWheelEventDeltaAxis1 = 11 # Y
38
+ KCGScrollWheelEventDeltaAxis2 = 12 # X
39
+
40
+ KCGEventKeyDown = 10
41
+ KCGEventKeyUp = 11
42
+ KCGEventFlagsChanged = 12
43
+
44
+ # We need to get the kCFRunLoopDefaultMode constant value
45
+ # It's a CFStringRef. For simplicity in FFI, we can often pass NULL (0) for default mode in some APIs,
46
+ # but CFRunLoopAddSource requires a mode.
47
+ # A common workaround is to look it up or define it if we know the symbol name.
48
+ # However, getting the actual pointer value of a constant exported by a dylib in FFI can be tricky.
49
+ # We'll try to attach it.
50
+ attach_variable :kCFRunLoopDefaultMode, :kCFRunLoopDefaultMode, :pointer
51
+
52
+ # CGEventTapCallback function signature
53
+ # @param proxy [CGEventTapProxy]
54
+ # @param type [Integer] The event type
55
+ # @param event [CGEventRef] The event reference
56
+ # @param refcon [Pointer] User data
57
+ # @return [CGEventRef] The event to pass through, or NULL to suppress
58
+ callback :CGEventTapCallback, [:pointer, :int, :pointer, :pointer], :pointer
59
+
60
+ # Functions
61
+
62
+ # Creates an event tap.
63
+ # @param tapLocation [Integer]
64
+ # @param place [Integer]
65
+ # @param options [Integer]
66
+ # @param eventsOfInterest [Integer] Mask of events to listen for
67
+ # @param callback [Proc] Block to be called
68
+ # @param userInfo [Pointer]
69
+ # @return [CFMachPortRef]
70
+ attach_function :CGEventTapCreate, [:int, :int, :int, :uint64, :CGEventTapCallback, :pointer], :CFMachPortRef
71
+
72
+ # Enables or disables an event tap.
73
+ # @param tap [CFMachPortRef]
74
+ # @param enable [Boolean]
75
+ attach_function :CGEventTapEnable, [:CFMachPortRef, :bool], :void
76
+
77
+ # Creates a run loop source for a Mach port.
78
+ # @param allocator [Pointer]
79
+ # @param port [CFMachPortRef]
80
+ # @param order [Integer]
81
+ # @return [CFRunLoopSourceRef]
82
+ attach_function :CFMachPortCreateRunLoopSource, [:pointer, :CFMachPortRef, :long], :CFRunLoopSourceRef
83
+
84
+ # Returns the current run loop.
85
+ # @return [CFRunLoopRef]
86
+ attach_function :CFRunLoopGetCurrent, [], :CFRunLoopRef
87
+
88
+ # Adds a source to a run loop mode.
89
+ # @param rl [CFRunLoopRef]
90
+ # @param source [CFRunLoopSourceRef]
91
+ # @param mode [CFStringRef]
92
+ attach_function :CFRunLoopAddSource, [:CFRunLoopRef, :CFRunLoopSourceRef, :pointer], :void
93
+
94
+ # Runs the current run loop in a specific mode.
95
+ # @param mode [CFStringRef]
96
+ # @param seconds [Float]
97
+ # @param returnAfterSourceHandled [Boolean]
98
+ # @return [Integer] Result code
99
+ attach_function :CFRunLoopRunInMode, [:pointer, :double, :bool], :int
100
+
101
+ # Stops a run loop.
102
+ # @param rl [CFRunLoopRef]
103
+ attach_function :CFRunLoopStop, [:CFRunLoopRef], :void
104
+
105
+ # RE-DEFINED: Removes a value from a retain/release system.
106
+ # This was defined twice in the original file, keeping one.
107
+ # @param cf [Pointer]
108
+ attach_function :CFRelease, [:pointer], :void
109
+
110
+ # Checks if the current process is trusted for accessibility.
111
+ # @return [Boolean]
112
+ attach_function :AXIsProcessTrusted, [], :bool
113
+
114
+ # Gets an integer value from an event field.
115
+ # @param event [CGEventRef]
116
+ # @param field [Integer]
117
+ # @return [Integer]
118
+ attach_function :CGEventGetIntegerValueField, [:pointer, :int], :int64
119
+
120
+ # Gets the event type.
121
+ # @param event [CGEventRef]
122
+ # @return [Integer]
123
+ attach_function :CGEventGetType, [:pointer], :int
124
+
125
+ # Gets the event flags.
126
+ # @param event [CGEventRef]
127
+ # @return [Integer]
128
+ attach_function :CGEventGetFlags, [:pointer], :uint64
129
+
130
+ # Creates a keyboard event.
131
+ # @param source [Pointer]
132
+ # @param virtualKey [Integer]
133
+ # @param keyDown [Boolean]
134
+ # @return [CGEventRef]
135
+ attach_function :CGEventCreateKeyboardEvent, [:pointer, :uint16, :bool], :pointer
136
+
137
+ # Posts an event to the event stream.
138
+ # @param tapLocation [Integer]
139
+ # @param event [CGEventRef]
140
+ attach_function :CGEventPost, [:int, :pointer], :void
141
+
142
+ # Creates an event source.
143
+ # @param stateID [Integer]
144
+ # @return [Pointer]
145
+ attach_function :CGEventSourceCreate, [:int], :pointer
146
+
147
+ # Sets the event flags.
148
+ # @param event [CGEventRef]
149
+ # @param flags [Integer]
150
+ attach_function :CGEventSetFlags, [:pointer, :uint64], :void
151
+ end
68
152
  end
@@ -7,83 +7,122 @@ require_relative './darwin_ffi'
7
7
 
8
8
  module Rbnput
9
9
  # Base listener for keyboard events
10
+ # คลาส Listener พื้นฐานสำหรับเหตุการณ์คีย์บอร์ด บน macOS
10
11
  class DarwinListener < Rbnput::SimpleMutexThread
12
+ # Initializes the DarwinListener.
13
+ # สร้าง instance ใหม่สำหรับดักจับคีย์บอร์ด
14
+ #
15
+ # @param on_press [Proc, nil] Callback when a key is pressed.
16
+ # @param on_release [Proc, nil] Callback when a key is released.
17
+ # @param kwargs [Hash] Additional options passed to SimpleMutexThread.
11
18
  def initialize(on_press: nil, on_release: nil, **kwargs)
12
19
  super(*kwargs)
13
- @on_press = on_press
14
- @on_release = on_release
20
+ @on_press = on_press # callback เมื่อกดปุ่ม
21
+ @on_release = on_release # callback เมื่อปล่อยปุ่ม
15
22
 
16
23
  @loop = nil
17
24
  @tap = nil
18
- @callback_proc = nil # Keep reference to prevent GC
25
+ @callback_proc = nil # Keep reference to prevent GC (เก็บ reference ไว้เพื่อป้องกัน Garbage Collection)
19
26
  end
20
27
  attr_reader :on_press, :on_release
21
28
 
29
+ # Sets the callback for key press events.
30
+ # ตั้งค่า callback สำหรับการกดปุ่ม
31
+ #
32
+ # @yield [key]
33
+ # @yieldparam key [KeyCode] The key that was pressed.
22
34
  def on_press(&proc)
23
35
  @on_press = proc
24
36
  end
37
+
38
+ # Sets the callback for key release events.
39
+ # ตั้งค่า callback สำหรับการปล่อยปุ่ม
40
+ #
41
+ # @yield [key]
42
+ # @yieldparam key [KeyCode] The key that was released.
25
43
  def on_release(&proc)
26
- @on_press = proc
44
+ @on_release = proc
27
45
  end
28
46
 
47
+ # The main run loop for the listener.
48
+ # Internal method called by the thread.
49
+ #
50
+ # @api private
29
51
  def _run
52
+ # ตรวจสอบว่า Process ได้รับสิทธิ์ Accessibility หรือไม่
30
53
  unless Rbnput::DarwinFFI.AXIsProcessTrusted()
31
54
  @log.warn("Process is not trusted! Input monitoring will not work until added to accessibility clients.")
55
+ @log.warn("โปรแกรมนี้ยังไม่ได้รับสิทธิ์ Accessibility! การดักจับอินพุตจะไม่ทำงานจนกว่าจะได้รับอนุญาต")
32
56
  end
33
57
 
34
58
  # Create the callback
59
+ # สร้าง callback function ที่จะถูกเรียกเมื่อมี event
35
60
  @callback_proc = FFI::Function.new(:pointer, [:pointer, :int, :pointer, :pointer]) do |proxy, type, event, refcon|
61
+ # ดึงค่า key code จาก event และแปลงเป็น KeyCode object
36
62
  key_code = DarwinFFI
37
63
  .CGEventGetIntegerValueField(event, Rbnput::DarwinFFI::KCGKeyboardEventKeycode)
38
64
  .then { |vk| KeyCode.from_vk(vk) }
39
65
 
40
66
  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)
67
+ when Rbnput::DarwinFFI::KCGEventKeyDown; @on_press&.call(key_code) # กดปุ่ม
68
+ when Rbnput::DarwinFFI::KCGEventKeyUp; @on_release&.call(key_code) # ปล่อยปุ่ม
69
+ when Rbnput::DarwinFFI::KCGEventFlagsChanged; @on_press&.call(key_code) # ปุ่ม Modifier เปลี่ยนแปลง (เช่น Shift, Ctrl)
44
70
  end
45
71
  event
46
72
  end
47
73
 
74
+ # สร้าง Event Tap เพื่อดักจับ event ของระบบ
48
75
  @tap = Rbnput::DarwinFFI.CGEventTapCreate(
49
76
  Rbnput::DarwinFFI::KCGSessionEventTap,
50
77
  Rbnput::DarwinFFI::KCGHeadInsertEventTap,
51
78
  Rbnput::DarwinFFI::KCGEventTapOptionDefault,
52
- (1 << Rbnput::DarwinFFI::KCGEventKeyDown) | (1 << Rbnput::DarwinFFI::KCGEventKeyUp) | (1 << Rbnput::DarwinFFI::KCGEventFlagsChanged),
79
+ (1 << Rbnput::DarwinFFI::KCGEventKeyDown) | (1 << Rbnput::DarwinFFI::KCGEventKeyUp) | (1 << Rbnput::DarwinFFI::KCGEventFlagsChanged), # ระบุประเภท event ที่ต้องการดักจับ
53
80
  @callback_proc,
54
81
  nil
55
82
  )
56
83
 
57
84
  if @tap.null?
58
85
  @log.error("Failed to create event tap")
86
+ @log.error("ไม่สามารถสร้าง event tap ได้")
59
87
  return
60
88
  end
61
89
 
62
90
  # Create run loop source
91
+ # สร้าง run loop source จาก tap
63
92
  source = Rbnput::DarwinFFI.CFMachPortCreateRunLoopSource(nil, @tap, 0)
64
93
 
65
94
  # Add to current run loop
95
+ # เพิ่ม source เข้าไปใน run loop ปัจจุบัน
66
96
  @loop = Rbnput::DarwinFFI.CFRunLoopGetCurrent()
67
97
  Rbnput::DarwinFFI.CFRunLoopAddSource(@loop, source, Rbnput::DarwinFFI.kCFRunLoopDefaultMode)
68
98
 
69
99
  # Enable tap
100
+ # เปิดใช้งาน tap
70
101
  Rbnput::DarwinFFI.CGEventTapEnable(@tap, true)
71
102
 
72
103
  # Run loop
104
+ # เริ่มทำงาน loop เพื่อรอรับ event
73
105
  while @running
74
106
  _result = Rbnput::DarwinFFI.CFRunLoopRunInMode(Rbnput::DarwinFFI.kCFRunLoopDefaultMode, 0.1, false)
75
107
 
76
108
  # 0.1 second timeout allows us to check @running flag
109
+ # timeout 0.1 วินาที เพื่อให้สามารถตรวจสอบ flag @running ได้ (เพื่อให้หยุด loop ได้อย่างนุ่มนวล)
77
110
  end
78
111
  ensure
112
+ # Cleanup เมื่อจบการทำงาน
79
113
  Rbnput::DarwinFFI.CFRelease(@tap) if @tap && !@tap.null?
80
114
  Rbnput::DarwinFFI.CFRelease(source) if source && !source.null?
81
115
  @tap = nil
82
116
  @loop = nil
83
117
  end
84
118
 
119
+ # Stops the listener and the run loop.
120
+ # หยุดการทำงานของ listener
121
+ #
122
+ # @return [void]
85
123
  def stop
86
124
  super
125
+ # หยุด run loop
87
126
  Rbnput::DarwinFFI.CFRunLoopStop(@loop) if @loop && !@loop.null?
88
127
  end
89
128
 
@@ -3,11 +3,15 @@ require_relative "./key_code_const"
3
3
  class Rbnput::KeyCode
4
4
  attr_reader :vk, :is_media
5
5
 
6
+ # สร้าง Object KeyCode
7
+ # @param vk [Integer] Virtual Key Code
8
+ # @param is_media [Boolean] เป็น Media Key หรือไม่
6
9
  def initialize(vk: nil, is_media: false)
7
10
  @vk = vk
8
11
  @is_media = is_media
9
12
  end
10
13
 
14
+ # แปลงเป็น String สำหรับแสดงผล
11
15
  def to_s
12
16
  [
13
17
  @vk.nil? ? "" : "vk=#{@vk}",
@@ -18,10 +22,12 @@ class Rbnput::KeyCode
18
22
  .then { "KeyCode(#{_1}, #{key})" }
19
23
  end
20
24
 
25
+ # ชื่อของปุ่ม (จากค่า vk)
21
26
  def key
22
27
  KEY_CODE_HEX_TO_NAME[@vk] || "UNKNOW"
23
28
  end
24
29
 
30
+ # เปรียบเทียบ object
25
31
  def ==(other)
26
32
  return false unless other.is_a?(KeyCode)
27
33
  @vk == other.vk && @is_media == other.is_media
@@ -33,10 +39,12 @@ class Rbnput::KeyCode
33
39
  [@vk, @is_media].hash
34
40
  end
35
41
 
42
+ # สร้าง KeyCode จาก Virtual Key
36
43
  def self.from_vk(vk, **kwargs)
37
44
  new(vk: vk, is_media: false, **kwargs)
38
45
  end
39
46
 
47
+ # สร้าง KeyCode จาก Media Key
40
48
  def self.from_media(vk, **kwargs)
41
49
  new(vk: vk, is_media: true, **kwargs)
42
50
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Mapping from key names to macOS unique virtual key codes (Hex).
4
+ # Based on the system header files.
1
5
  KEY_CODE_NAME_TO_HEX = {
2
6
  :kVK_ANSI_A => 0x00,
3
7
  :kVK_ANSI_S => 0x01,
@@ -125,4 +129,5 @@ KEY_CODE_NAME_TO_HEX = {
125
129
  # NX_KEYTYPE_REWIND = 20
126
130
  }
127
131
 
132
+ # Reverse mapping from virtual key codes to key names.
128
133
  KEY_CODE_HEX_TO_NAME = KEY_CODE_NAME_TO_HEX.invert
@@ -2,22 +2,35 @@
2
2
 
3
3
  require 'thread'
4
4
 
5
+ # A simple thread wrapper with mutex synchronization.
6
+ # Provides a base class for threaded listeners.
5
7
  class Rbnput::SimpleMutexThread
6
8
 
7
9
  protected
8
- # Platform-specific run implementation
9
- # Must be implemented by subclasses
10
+
11
+ # Platform-specific run implementation.
12
+ # Must be implemented by subclasses.
13
+ #
14
+ # @return [void]
15
+ # @raise [NotImplementedError] If not implemented by subclass
10
16
  def _run; raise NotImplementedError, "Subclasses must implement _run" end
11
17
 
12
18
  public
19
+
20
+ # @return [Boolean] true if the thread is running
13
21
  attr_reader :running
22
+
23
+ # Initializes the SimpleMutexThread.
14
24
  def initialize
15
25
  @running = false
16
26
  @thread = nil
17
27
  @mutex = Mutex.new
18
28
  end
19
29
 
20
- # Start the listener in a separate thread
30
+ # Starts the listener in a separate thread.
31
+ # Check is running before start new thread.
32
+ #
33
+ # @return [self]
21
34
  def start
22
35
  @mutex.synchronize do
23
36
  return if @running
@@ -30,14 +43,24 @@ class Rbnput::SimpleMutexThread
30
43
  self
31
44
  end
32
45
 
33
- # Stop the listener
46
+ # Stops the listener.
47
+ # Sets running flag to false and waits for the thread to exit.
48
+ #
49
+ # @return [self]
34
50
  def stop
35
51
  @mutex.synchronize do; @running = false end
36
52
  @thread&.join(5) # Wait up to 5 seconds
37
53
  self
38
54
  end
39
55
 
56
+ # Joins the thread.
57
+ #
58
+ # @return [Thread, nil]
40
59
  def join; @thread&.join end
60
+
61
+ # Checks if the thread is alive.
62
+ #
63
+ # @return [Boolean]
41
64
  def alive?; @running && @thread&.alive? end
42
65
 
43
66
 
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rbnput
4
- VERSION = "0.2.0"
4
+ # Current version of the gem
5
+ VERSION = "1.4.0"
6
+
7
+ # Gem Author
5
8
  AUTHOR = "Krist Ponpairin"
6
9
  end
@@ -18,9 +18,12 @@ require_relative "rbnput/darwin_listener"
18
18
  # require_relative "rbnput/mouse"
19
19
 
20
20
  # The main Rbnput module
21
+ # โมดูลหลักสำหรับ Rbnput
21
22
  #
22
23
  # This module imports keyboard and mouse submodules for controlling
23
24
  # and monitoring input devices.
25
+ # โมดูลนี้จะนำเข้าโมดูลย่อยของคีย์บอร์ดและเมาส์เพื่อควบคุมและตรวจสอบอุปกรณ์อินพุต
24
26
  module Rbnput
27
+ # กำหนด Listener เป็น DarwinListener สำหรับระบบ macOS
25
28
  Listener = ::Rbnput::DarwinListener
26
29
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbnput-darwin-minimal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Krist Ponpairin
@@ -29,7 +29,8 @@ email:
29
29
  - krist7599555@gmail.com
30
30
  executables: []
31
31
  extensions: []
32
- extra_rdoc_files: []
32
+ extra_rdoc_files:
33
+ - README.md
33
34
  files:
34
35
  - LICENSE
35
36
  - README.md