raxon-barcode-scanner 0.1.2 → 0.1.5

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.
@@ -1,8 +1,8 @@
1
1
  import { NativeModule } from 'expo';
2
2
  import { BarcodeScannerOptions, RaxonBarcodeScannerModuleEvents } from './RaxonBarcodeScanner.types';
3
3
  declare class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {
4
- startListening(options?: BarcodeScannerOptions): void;
5
- stopListening(): void;
4
+ startListening(options: BarcodeScannerOptions): Promise<void>;
5
+ stopListening(): Promise<void>;
6
6
  }
7
7
  declare const _default: RaxonBarcodeScannerModule;
8
8
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"RaxonBarcodeScannerModule.d.ts","sourceRoot":"","sources":["../src/RaxonBarcodeScannerModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAChC,MAAM,6BAA6B,CAAC;AAErC,OAAO,OAAO,yBAA0B,SAAQ,YAAY,CAAC,+BAA+B,CAAC;IAC3F,cAAc,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,IAAI;IACrD,aAAa,IAAI,IAAI;CACtB;;AAED,wBAAqF"}
1
+ {"version":3,"file":"RaxonBarcodeScannerModule.d.ts","sourceRoot":"","sources":["../src/RaxonBarcodeScannerModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAChC,MAAM,6BAA6B,CAAC;AAErC,OAAO,OAAO,yBAA0B,SAAQ,YAAY,CAAC,+BAA+B,CAAC;IAC3F,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC7D,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;CAC/B;;AAED,wBAAqF"}
@@ -1 +1 @@
1
- {"version":3,"file":"RaxonBarcodeScannerModule.js","sourceRoot":"","sources":["../src/RaxonBarcodeScannerModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAYzD,eAAe,mBAAmB,CAA4B,qBAAqB,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\nimport {\n BarcodeScannerOptions,\n RaxonBarcodeScannerModuleEvents,\n} from './RaxonBarcodeScanner.types';\n\ndeclare class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {\n startListening(options?: BarcodeScannerOptions): void;\n stopListening(): void;\n}\n\nexport default requireNativeModule<RaxonBarcodeScannerModule>('RaxonBarcodeScanner');\n"]}
1
+ {"version":3,"file":"RaxonBarcodeScannerModule.js","sourceRoot":"","sources":["../src/RaxonBarcodeScannerModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAYzD,eAAe,mBAAmB,CAA4B,qBAAqB,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\nimport {\n BarcodeScannerOptions,\n RaxonBarcodeScannerModuleEvents,\n} from './RaxonBarcodeScanner.types';\n\ndeclare class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {\n startListening(options: BarcodeScannerOptions): Promise<void>;\n stopListening(): Promise<void>;\n}\n\nexport default requireNativeModule<RaxonBarcodeScannerModule>('RaxonBarcodeScanner');\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useBarcodeScanner.d.ts","sourceRoot":"","sources":["../src/useBarcodeScanner.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,6BAA6B,CAAC;AAGrC,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,EACpD,OAAO,CAAC,EAAE,qBAAqB,GAC9B,uBAAuB,CA+BzB"}
1
+ {"version":3,"file":"useBarcodeScanner.d.ts","sourceRoot":"","sources":["../src/useBarcodeScanner.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,6BAA6B,CAAC;AAGrC,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,EACpD,OAAO,CAAC,EAAE,qBAAqB,GAC9B,uBAAuB,CAmCzB"}
@@ -9,12 +9,15 @@ export function useBarcodeScanner(enabled, onReadBarcode, options) {
9
9
  if (!enabled) {
10
10
  return;
11
11
  }
12
- RaxonBarcodeScanner.startListening(options);
13
- const subscription = RaxonBarcodeScanner.addListener('onBarcodeScanned', (event) => {
14
- onReadBarcodeRef.current(event);
15
- });
12
+ let subscription = null;
13
+ (async () => {
14
+ await RaxonBarcodeScanner.startListening(options ?? {});
15
+ subscription = RaxonBarcodeScanner.addListener('onBarcodeScanned', (event) => {
16
+ onReadBarcodeRef.current(event);
17
+ });
18
+ })();
16
19
  return () => {
17
- subscription.remove();
20
+ subscription?.remove();
18
21
  RaxonBarcodeScanner.stopListening();
19
22
  };
20
23
  }, [
@@ -1 +1 @@
1
- {"version":3,"file":"useBarcodeScanner.js","sourceRoot":"","sources":["../src/useBarcodeScanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAO1C,OAAO,mBAAmB,MAAM,6BAA6B,CAAC;AAE9D,MAAM,UAAU,iBAAiB,CAC/B,OAAgB,EAChB,aAAoD,EACpD,OAA+B;IAE/B,MAAM,gBAAgB,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;IAE/C,SAAS,CAAC,GAAG,EAAE;QACb,gBAAgB,CAAC,OAAO,GAAG,aAAa,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,mBAAmB,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAE5C,MAAM,YAAY,GAAG,mBAAmB,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE;YACjF,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,YAAY,CAAC,MAAM,EAAE,CAAC;YACtB,mBAAmB,CAAC,aAAa,EAAE,CAAC;QACtC,CAAC,CAAC;IACJ,CAAC,EAAE;QACD,OAAO;QACP,OAAO,EAAE,YAAY;QACrB,OAAO,EAAE,WAAW;QACpB,OAAO,EAAE,kBAAkB;QAC3B,OAAO,EAAE,eAAe;KACzB,CAAC,CAAC;IAEH,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC","sourcesContent":["import { useEffect, useRef } from 'react';\n\nimport {\n BarcodeScanPayload,\n BarcodeScannerOptions,\n UseBarcodeScannerResult,\n} from './RaxonBarcodeScanner.types';\nimport RaxonBarcodeScanner from './RaxonBarcodeScannerModule';\n\nexport function useBarcodeScanner(\n enabled: boolean,\n onReadBarcode: (payload: BarcodeScanPayload) => void,\n options?: BarcodeScannerOptions\n): UseBarcodeScannerResult {\n const onReadBarcodeRef = useRef(onReadBarcode);\n\n useEffect(() => {\n onReadBarcodeRef.current = onReadBarcode;\n });\n\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n RaxonBarcodeScanner.startListening(options);\n\n const subscription = RaxonBarcodeScanner.addListener('onBarcodeScanned', (event) => {\n onReadBarcodeRef.current(event);\n });\n\n return () => {\n subscription.remove();\n RaxonBarcodeScanner.stopListening();\n };\n }, [\n enabled,\n options?.intentAction,\n options?.profileName,\n options?.configureDataWedge,\n options?.captureKeyboard,\n ]);\n\n return { isListening: enabled };\n}\n"]}
1
+ {"version":3,"file":"useBarcodeScanner.js","sourceRoot":"","sources":["../src/useBarcodeScanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAO1C,OAAO,mBAAmB,MAAM,6BAA6B,CAAC;AAE9D,MAAM,UAAU,iBAAiB,CAC/B,OAAgB,EAChB,aAAoD,EACpD,OAA+B;IAE/B,MAAM,gBAAgB,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;IAE/C,SAAS,CAAC,GAAG,EAAE;QACb,gBAAgB,CAAC,OAAO,GAAG,aAAa,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,IAAI,YAAY,GAAkC,IAAI,CAAC;QAEvD,CAAC,KAAK,IAAI,EAAE;YACV,MAAM,mBAAmB,CAAC,cAAc,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YAExD,YAAY,GAAG,mBAAmB,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC3E,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,EAAE,CAAC;QAEL,OAAO,GAAG,EAAE;YACV,YAAY,EAAE,MAAM,EAAE,CAAC;YACvB,mBAAmB,CAAC,aAAa,EAAE,CAAC;QACtC,CAAC,CAAC;IACJ,CAAC,EAAE;QACD,OAAO;QACP,OAAO,EAAE,YAAY;QACrB,OAAO,EAAE,WAAW;QACpB,OAAO,EAAE,kBAAkB;QAC3B,OAAO,EAAE,eAAe;KACzB,CAAC,CAAC;IAEH,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC","sourcesContent":["import { useEffect, useRef } from 'react';\n\nimport {\n BarcodeScanPayload,\n BarcodeScannerOptions,\n UseBarcodeScannerResult,\n} from './RaxonBarcodeScanner.types';\nimport RaxonBarcodeScanner from './RaxonBarcodeScannerModule';\n\nexport function useBarcodeScanner(\n enabled: boolean,\n onReadBarcode: (payload: BarcodeScanPayload) => void,\n options?: BarcodeScannerOptions\n): UseBarcodeScannerResult {\n const onReadBarcodeRef = useRef(onReadBarcode);\n\n useEffect(() => {\n onReadBarcodeRef.current = onReadBarcode;\n });\n\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n let subscription: { remove: () => void } | null = null;\n\n (async () => {\n await RaxonBarcodeScanner.startListening(options ?? {});\n\n subscription = RaxonBarcodeScanner.addListener('onBarcodeScanned', (event) => {\n onReadBarcodeRef.current(event);\n });\n })();\n\n return () => {\n subscription?.remove();\n RaxonBarcodeScanner.stopListening();\n };\n }, [\n enabled,\n options?.intentAction,\n options?.profileName,\n options?.configureDataWedge,\n options?.captureKeyboard,\n ]);\n\n return { isListening: enabled };\n}\n"]}
@@ -10,10 +10,11 @@ Pod::Spec.new do |s|
10
10
  s.license = package['license']
11
11
  s.author = package['author']
12
12
  s.homepage = package['homepage']
13
- s.platform = :ios, '13.4'
13
+ s.platform = :ios, '15.1'
14
14
  s.swift_version = '5.4'
15
15
  s.source = { git: 'https://github.com/raxonltd/raxon-barcode-scanner.git' }
16
16
  s.static_framework = true
17
+ s.frameworks = 'GameController'
17
18
 
18
19
  s.dependency 'ExpoModulesCore'
19
20
 
@@ -1,14 +1,15 @@
1
1
  import ExpoModulesCore
2
+ import GameController
2
3
  import UIKit
3
4
 
4
5
  // MARK: - RaxonBarcodeScannerModule
5
6
 
6
7
  /// iOS için Bluetooth ve HID barkod okuyucu desteği sağlayan Expo modülü.
7
- /// Harici klavye olarak davranan Bluetooth barkod okuyucuların tuş vuruşlarını yakalar.
8
+ /// GameController framework'ün GCKeyboard API'si ile donanım klavyesi tuşlarını
9
+ /// responder chain'den bağımsız olarak, sistem seviyesinde yakalar.
8
10
  public final class RaxonBarcodeScannerModule: Module {
9
11
  private var isListening = false
10
- private var captureKeyboard = true
11
- private var keyboardHandler: ExternalKeyboardHandler?
12
+ private var keyboardMonitor: HardwareKeyboardMonitor?
12
13
 
13
14
  public required init(appContext: AppContext) {
14
15
  super.init(appContext: appContext)
@@ -19,12 +20,16 @@ public final class RaxonBarcodeScannerModule: Module {
19
20
 
20
21
  Events("onBarcodeScanned")
21
22
 
22
- Function("startListening") { (options: [String: Any]?) in
23
- self.startListening(options: options)
23
+ AsyncFunction("startListening") { (options: [String: Any]?) in
24
+ await MainActor.run {
25
+ self.startListening(options: options)
26
+ }
24
27
  }
25
28
 
26
- Function("stopListening") {
27
- self.stopListening()
29
+ AsyncFunction("stopListening") {
30
+ await MainActor.run {
31
+ self.stopListening()
32
+ }
28
33
  }
29
34
 
30
35
  OnDestroy {
@@ -33,296 +38,159 @@ public final class RaxonBarcodeScannerModule: Module {
33
38
  }
34
39
 
35
40
  private func startListening(options: [String: Any]?) {
36
- guard !isListening else {
37
- stopListening()
38
- }
41
+ guard !isListening else { return }
39
42
 
40
- captureKeyboard = options?["captureKeyboard"] as? Bool ?? true
43
+ let captureKeyboard = options?["captureKeyboard"] as? Bool ?? true
41
44
 
42
45
  if captureKeyboard {
43
- setupKeyboardCapture()
46
+ let monitor = HardwareKeyboardMonitor()
47
+ monitor.onBarcodeScanned = { [weak self] code in
48
+ self?.sendEvent("onBarcodeScanned", ["code": code])
49
+ }
50
+ monitor.start()
51
+ keyboardMonitor = monitor
44
52
  }
45
53
 
46
54
  isListening = true
47
55
  }
48
56
 
49
57
  private func stopListening() {
50
- teardownKeyboardCapture()
58
+ keyboardMonitor?.stop()
59
+ keyboardMonitor = nil
51
60
  isListening = false
52
61
  }
53
-
54
- private func setupKeyboardCapture() {
55
- guard let viewController = appContext?.currentViewController else {
56
- return
57
- }
58
-
59
- if #available(iOS 13.4, *) {
60
- keyboardHandler = ExternalKeyboardHandler(
61
- viewController: viewController,
62
- onBarcodeScanned: { [weak self] code in
63
- self?.sendEvent("onBarcodeScanned", ["code": code])
64
- }
65
- )
66
- keyboardHandler?.startListening()
67
- }
68
- }
69
-
70
- private func teardownKeyboardCapture() {
71
- keyboardHandler?.stopListening()
72
- keyboardHandler = nil
73
- }
74
62
  }
75
63
 
76
- // MARK: - ExternalKeyboardHandler
64
+ // MARK: - HardwareKeyboardMonitor
77
65
 
78
- /// iOS 13.4+ için harici klavye (Bluetooth barkod okuyucu) girişini yakalayan sınıf.
79
- /// pressesBegan/pressesEnded API'sini kullanarak fiziksel klavye tuşlarını yakalar.
80
- @available(iOS 13.4, *)
81
- private final class ExternalKeyboardHandler {
82
- private weak var viewController: UIViewController?
83
- private let onBarcodeScanned: (String) -> Void
84
- private var keyBuffer: String = ""
85
- private var lastKeyTime: TimeInterval = 0
86
- private let bufferTimeout: TimeInterval = 1.0
87
-
88
- // Terminatör tuş kodları
89
- private let terminatorKeyCodes: Set<Int> = [
90
- 36, // Return/Enter
91
- 76, // Numpad Enter
92
- 48, // Tab
93
- 52, // Numpad Equal (bazı okuyucularda)
94
- 67, // Numpad Asterisk (bazı okuyucularda)
95
- ]
66
+ /// GCKeyboard ile donanım klavyesi (Bluetooth barkod okuyucu) girişini izler.
67
+ /// Responder chain'e bağımlı olmadığı için tuş kaybı yaşanmaz ve
68
+ /// ekrandaki input'lar ile etkileşime girmez.
69
+ private final class HardwareKeyboardMonitor {
70
+ var onBarcodeScanned: ((String) -> Void)?
96
71
 
97
- init(viewController: UIViewController, onBarcodeScanned: @escaping (String) -> Void) {
98
- self.viewController = viewController
99
- self.onBarcodeScanned = onBarcodeScanned
100
- }
72
+ private var keyBuffer = ""
73
+ private var lastKeyTime: TimeInterval = 0
74
+ // Tuşlar arası bu süre aşılırsa tampon sıfırlanır (insan yazısını barkoddan ayırır)
75
+ private let bufferTimeout: TimeInterval = 0.5
76
+ private var connectObserver: NSObjectProtocol?
77
+ private var attachedInputs: [ObjectIdentifier: GCKeyboardInput] = [:]
101
78
 
102
- func startListening() {
103
- // pressesBegan/pressesEnded metodlarını sarmalamak için swizzling kullanacağız
104
- swizzlePressesMethods()
79
+ func start() {
80
+ // Halihazırda bağlı klavye varsa hemen dinlemeye başla
81
+ attach(to: GCKeyboard.coalesced)
105
82
 
106
- // Ayrıca UIResponder chain'den gelen tuş olaylarını da dinle
107
- setupKeyCommandHandling()
83
+ // Sonradan bağlanan klavyeler (örn. Bluetooth okuyucu) için bildirim dinle
84
+ connectObserver = NotificationCenter.default.addObserver(
85
+ forName: .GCKeyboardDidConnect,
86
+ object: nil,
87
+ queue: .main
88
+ ) { [weak self] notification in
89
+ self?.attach(to: notification.object as? GCKeyboard)
90
+ }
108
91
  }
109
92
 
110
- func stopListening() {
111
- unswizzlePressesMethods()
93
+ func stop() {
94
+ if let connectObserver {
95
+ NotificationCenter.default.removeObserver(connectObserver)
96
+ }
97
+ connectObserver = nil
98
+
99
+ for (_, input) in attachedInputs {
100
+ input.keyChangedHandler = nil
101
+ }
102
+ attachedInputs.removeAll()
112
103
  keyBuffer = ""
113
104
  }
114
105
 
115
- private func setupKeyCommandHandling() {
116
- // UIKeyCommand kullanarak bazı özel tuşları yakalayabiliriz
117
- // Ancak tüm tuşları yakalamak için pressesBegan/pressesEnded daha iyi
118
- }
106
+ private func attach(to keyboard: GCKeyboard?) {
107
+ guard let input = keyboard?.keyboardInput else { return }
119
108
 
120
- // MARK: - Tuş İşleme
109
+ let id = ObjectIdentifier(input)
110
+ guard attachedInputs[id] == nil else { return }
111
+ attachedInputs[id] = input
121
112
 
122
- func handlePress(_ press: UIPress) -> Bool {
123
- guard let key = press.key else { return false }
113
+ input.keyChangedHandler = { [weak self] keyboardInput, _, keyCode, pressed in
114
+ guard pressed else { return }
115
+ self?.handleKey(keyCode, input: keyboardInput)
116
+ }
117
+ }
124
118
 
125
- let keyCode = key.keyCode.rawValue
119
+ private func handleKey(_ keyCode: GCKeyCode, input: GCKeyboardInput) {
126
120
  let now = Date().timeIntervalSince1970
127
-
128
- // Zaman aşımı kontrolü - tuşlar arası 1 saniyeden fazla varsa tamponu sıfırla
129
121
  if now - lastKeyTime > bufferTimeout {
130
122
  keyBuffer = ""
131
123
  }
132
124
  lastKeyTime = now
133
125
 
134
- // Terminatör tuş kontrolü
135
- if isTerminator(keyCode) {
136
- if !keyBuffer.isEmpty {
137
- let code = keyBuffer
138
- keyBuffer = ""
139
- onBarcodeScanned(code)
140
- return true // Tuşu yut
126
+ // Terminatör: Enter / Numpad Enter / Tab
127
+ if keyCode == .returnOrEnter || keyCode == .keypadEnter || keyCode == .tab {
128
+ let code = keyBuffer
129
+ keyBuffer = ""
130
+ if !code.isEmpty {
131
+ let callback = onBarcodeScanned
132
+ DispatchQueue.main.async {
133
+ callback?(code)
134
+ }
141
135
  }
142
- // Tampon boşken terminatörü normal davranışa bırak
143
- return false
144
- }
145
-
146
- // Karakter tuşu mu?
147
- if let char = characterFromKey(key) {
148
- keyBuffer.append(char)
149
- return true // Tuşu yut (UI'ya ulaşmasını engelle)
150
- }
151
-
152
- return false
153
- }
154
-
155
- private func isTerminator(_ keyCode: Int) -> Bool {
156
- return terminatorKeyCodes.contains(keyCode)
157
- }
158
-
159
- private func characterFromKey(_ key: UIKey) -> Character? {
160
- // Karakter önceliği:
161
- // 1. modifiersiz karakter (temel ASCII)
162
- // 2. modifiers varsa ve shift varsa büyük harf
163
-
164
- var char: Character?
165
-
166
- // UIKey.characters ile dene
167
- if let chars = key.characters, !chars.isEmpty {
168
- char = chars.first
136
+ return
169
137
  }
170
138
 
171
- // UIKey.charactersIgnoringModifiers ile dene (Shift/Ctrl/Alt olmadan)
172
- if char == nil, let chars = key.charactersIgnoringModifiers, !chars.isEmpty {
173
- char = chars.first
174
- }
139
+ let shiftPressed =
140
+ input.button(forKeyCode: .leftShift)?.isPressed == true ||
141
+ input.button(forKeyCode: .rightShift)?.isPressed == true
175
142
 
176
- // Eğer hala nil ise, keyCode'dan çevir
177
- if char == nil {
178
- char = characterFromKeyCode(key.keyCode.rawValue)
143
+ if let char = Self.character(for: keyCode, shifted: shiftPressed) {
144
+ keyBuffer.append(char)
179
145
  }
180
-
181
- return char
182
- }
183
-
184
- private func characterFromKeyCode(_ keyCode: Int) -> Character? {
185
- // iOS fiziksel klavye key kodlarından karakter dönüşümü
186
- // Bluetooth barkod okuyucular genellikle standart USB HID key kodları kullanır
187
- let mapping: [Int: Character] = [
188
- // Rakamlar (ana klavye)
189
- 23: "0", 22: "1", 26: "2", 20: "3", 25: "4",
190
- 29: "5", 27: "6", 24: "7", 28: "8", 21: "9",
191
-
192
- // Numpad rakamlar
193
- 98: "0", 89: "1", 90: "2", 91: "3", 92: "4",
194
- 93: "5", 94: "6", 95: "7", 96: "8", 97: "9",
195
-
196
- // Harfler (ana klavye)
197
- 12: "q", 13: "w", 14: "e", 15: "r", 17: "t",
198
- 16: "y", 32: "u", 34: "i", 31: "o", 35: "p",
199
- 0: "a", 1: "s", 2: "d", 3: "f", 5: "g",
200
- 4: "h", 38: "k", 37: "j", 40: "l", 6: "z",
201
- 7: "x", 8: "c", 9: "v", 11: "b", 45: "n",
202
- 46: "m",
203
-
204
- // Özel karakterler
205
- 51: "\u{0008}", // Backspace (silme)
206
- 117: "\u{007F}", // Delete
207
- 42: ",", 43: "-", 44: ".", 47: "/",
208
- 39: "'", 33: "[", 30: "]", 41: ";", 50: "`",
209
- 115: "\u{001B}", // Escape
210
-
211
- // Boşluk
212
- 49: " ",
213
- ]
214
-
215
- return mapping[keyCode]
216
146
  }
217
147
 
218
- // MARK: - Method Swizzling
219
-
220
- private func swizzlePressesMethods() {
221
- guard let viewController = viewController else { return }
222
-
223
- let originalPressesBeganSelector = #selector(UIViewController.pressesBegan(_:with:))
224
- let swizzledPressesBeganSelector = #selector(UIViewController.raxon_pressesBegan(_:with:))
225
-
226
- let originalPressesEndedSelector = #selector(UIViewController.pressesEnded(_:with:))
227
- let swizzledPressesEndedSelector = #selector(UIViewController.raxon_pressesEnded(_:with:))
228
-
229
- swizzleMethod(
230
- for: UIViewController.self,
231
- originalSelector: originalPressesBeganSelector,
232
- swizzledSelector: swizzledPressesBeganSelector
233
- )
234
-
235
- swizzleMethod(
236
- for: UIViewController.self,
237
- originalSelector: originalPressesEndedSelector,
238
- swizzledSelector: swizzledPressesEndedSelector
239
- )
240
-
241
- // Bu view controller'a weak referans ile handler'a erişim sağla
242
- objc_setAssociatedObject(
243
- viewController,
244
- &AssociatedKeys.keyboardHandler,
245
- self,
246
- .OBJC_ASSOCIATION_RETAIN_NONATOMIC
247
- )
248
- }
249
-
250
- private func unswizzlePressesMethods() {
251
- // Method swizzling geri alınamaz ama handler'ı temizleyebiliriz
252
- if let viewController = viewController {
253
- objc_setAssociatedObject(
254
- viewController,
255
- &AssociatedKeys.keyboardHandler,
256
- nil,
257
- .OBJC_ASSOCIATION_RETAIN_NONATOMIC
258
- )
259
- }
260
- }
148
+ // MARK: - GCKeyCode → Karakter eşleştirmesi
261
149
 
262
- private func swizzleMethod(
263
- for classType: AnyClass,
264
- originalSelector: Selector,
265
- swizzledSelector: Selector
266
- ) {
267
- guard let originalMethod = class_getInstanceMethod(classType, originalSelector),
268
- let swizzledMethod = class_getInstanceMethod(classType, swizzledSelector) else {
269
- return
150
+ private static func character(for keyCode: GCKeyCode, shifted: Bool) -> Character? {
151
+ if let letter = letters[keyCode] {
152
+ return shifted ? Character(letter.uppercased()) : letter
270
153
  }
271
-
272
- let didAddMethod = class_addMethod(
273
- classType,
274
- originalSelector,
275
- method_getImplementation(swizzledMethod),
276
- method_getTypeEncoding(swizzledMethod)
277
- )
278
-
279
- if didAddMethod {
280
- class_replaceMethod(
281
- classType,
282
- swizzledSelector,
283
- method_getImplementation(originalMethod),
284
- method_getTypeEncoding(originalMethod)
285
- )
286
- } else {
287
- method_exchangeImplementations(originalMethod, swizzledMethod)
154
+ if let pair = symbols[keyCode] {
155
+ return shifted ? pair.shifted : pair.normal
288
156
  }
157
+ return keypad[keyCode]
289
158
  }
290
- }
291
-
292
- // MARK: - AssociatedKeys
293
159
 
294
- private enum AssociatedKeys {
295
- static var keyboardHandler: UInt8 = 0
296
- }
297
-
298
- // MARK: - UIViewController Extension
299
-
300
- @available(iOS 13.4, *)
301
- extension UIViewController {
302
- @objc dynamic func raxon_pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
303
- // Orijinal implementasyonu çağır (swizzling yüzünden bu aslında orijinal)
304
- raxon_pressesBegan(presses, with: event)
160
+ private static let letters: [GCKeyCode: Character] = [
161
+ .keyA: "a", .keyB: "b", .keyC: "c", .keyD: "d", .keyE: "e",
162
+ .keyF: "f", .keyG: "g", .keyH: "h", .keyI: "i", .keyJ: "j",
163
+ .keyK: "k", .keyL: "l", .keyM: "m", .keyN: "n", .keyO: "o",
164
+ .keyP: "p", .keyQ: "q", .keyR: "r", .keyS: "s", .keyT: "t",
165
+ .keyU: "u", .keyV: "v", .keyW: "w", .keyX: "x", .keyY: "y",
166
+ .keyZ: "z",
167
+ ]
305
168
 
306
- // Handler varsa tuşları işle
307
- if let handler = objc_getAssociatedObject(self, &AssociatedKeys.keyboardHandler)
308
- as? ExternalKeyboardHandler {
309
- for press in presses {
310
- _ = handler.handlePress(press)
311
- }
312
- }
313
- }
169
+ private static let symbols: [GCKeyCode: (normal: Character, shifted: Character)] = [
170
+ .one: ("1", "!"), .two: ("2", "@"), .three: ("3", "#"),
171
+ .four: ("4", "$"), .five: ("5", "%"), .six: ("6", "^"),
172
+ .seven: ("7", "&"), .eight: ("8", "*"), .nine: ("9", "("),
173
+ .zero: ("0", ")"),
174
+ .spacebar: (" ", " "),
175
+ .hyphen: ("-", "_"),
176
+ .equalSign: ("=", "+"),
177
+ .openBracket: ("[", "{"),
178
+ .closeBracket: ("]", "}"),
179
+ .backslash: ("\\", "|"),
180
+ .semicolon: (";", ":"),
181
+ .quote: ("'", "\""),
182
+ .graveAccentAndTilde: ("`", "~"),
183
+ .comma: (",", "<"),
184
+ .period: (".", ">"),
185
+ .slash: ("/", "?"),
186
+ ]
314
187
 
315
- @objc dynamic func raxon_pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
316
- // Orijinal implementasyonu çağır
317
- raxon_pressesEnded(presses, with: event)
318
- }
188
+ private static let keypad: [GCKeyCode: Character] = [
189
+ .keypad0: "0", .keypad1: "1", .keypad2: "2", .keypad3: "3",
190
+ .keypad4: "4", .keypad5: "5", .keypad6: "6", .keypad7: "7",
191
+ .keypad8: "8", .keypad9: "9",
192
+ .keypadSlash: "/", .keypadAsterisk: "*",
193
+ .keypadHyphen: "-", .keypadPlus: "+",
194
+ .keypadPeriod: ".", .keypadEqualSign: "=",
195
+ ]
319
196
  }
320
-
321
- // MARK: - UIKey Extensions
322
-
323
- @available(iOS 13.4, *)
324
- extension UIKey {
325
- var keyCode: UIKeyboardHIDUsage {
326
- return self.keyCode
327
- }
328
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "raxon-barcode-scanner",
3
- "version": "0.1.2",
3
+ "version": "0.1.5",
4
4
  "description": "Zebra and enterprise barcode scanner hook for React Native Expo apps",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -46,7 +46,11 @@
46
46
  "expo-module.config.json",
47
47
  "src"
48
48
  ],
49
- "dependencies": {},
49
+ "dependencies": {
50
+ "expo": "~56.0.0-preview.9",
51
+ "react": "19.2.3",
52
+ "react-native": "0.85.3"
53
+ },
50
54
  "devDependencies": {
51
55
  "@babel/core": "^7.26.0",
52
56
  "@types/jest": "^29.2.1",
@@ -6,8 +6,8 @@ import {
6
6
  } from './RaxonBarcodeScanner.types';
7
7
 
8
8
  declare class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {
9
- startListening(options?: BarcodeScannerOptions): void;
10
- stopListening(): void;
9
+ startListening(options: BarcodeScannerOptions): Promise<void>;
10
+ stopListening(): Promise<void>;
11
11
  }
12
12
 
13
13
  export default requireNativeModule<RaxonBarcodeScannerModule>('RaxonBarcodeScanner');
@@ -23,14 +23,18 @@ export function useBarcodeScanner(
23
23
  return;
24
24
  }
25
25
 
26
- RaxonBarcodeScanner.startListening(options);
26
+ let subscription: { remove: () => void } | null = null;
27
27
 
28
- const subscription = RaxonBarcodeScanner.addListener('onBarcodeScanned', (event) => {
29
- onReadBarcodeRef.current(event);
30
- });
28
+ (async () => {
29
+ await RaxonBarcodeScanner.startListening(options ?? {});
30
+
31
+ subscription = RaxonBarcodeScanner.addListener('onBarcodeScanned', (event) => {
32
+ onReadBarcodeRef.current(event);
33
+ });
34
+ })();
31
35
 
32
36
  return () => {
33
- subscription.remove();
37
+ subscription?.remove();
34
38
  RaxonBarcodeScanner.stopListening();
35
39
  };
36
40
  }, [