Skip to content

Commit 0d511bd

Browse files
authored
Merge branch 'qiin2333:master' into master
2 parents 4053476 + b004e5c commit 0d511bd

File tree

11 files changed

+493
-8
lines changed

11 files changed

+493
-8
lines changed

app/src/main/java/com/limelight/Game.java

Lines changed: 289 additions & 0 deletions
Large diffs are not rendered by default.

app/src/main/java/com/limelight/PcView.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.limelight.preferences.GlPreferences;
3333
import com.limelight.preferences.PreferenceConfiguration;
3434
import com.limelight.preferences.StreamSettings;
35+
import com.limelight.services.KeyboardAccessibilityService;
3536
import com.limelight.ui.AdapterFragment;
3637
import com.limelight.ui.AdapterFragmentCallbacks;
3738
import com.limelight.utils.AnalyticsManager;
@@ -136,6 +137,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks, ShakeD
136137
private static final int SLEEP_ID = 12;
137138
private static final int IPERF3_TEST_ID = 13;
138139
private static final int SECONDARY_SCREEN_ID = 14;
140+
private static final int DISABLE_IPV6_ID = 15;
139141

140142
// UI Components
141143
private RelativeLayout noPcFoundLayout;
@@ -195,6 +197,28 @@ public void onServiceDisconnected(ComponentName className) {
195197
protected void onCreate(Bundle savedInstanceState) {
196198
super.onCreate(savedInstanceState);
197199

200+
//自动获取无障碍权限
201+
try {
202+
ComponentName cn = new ComponentName(this, KeyboardAccessibilityService.class);
203+
String myService = cn.flattenToString();
204+
String enabledServices = Settings.Secure.getString(getContentResolver(),
205+
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
206+
207+
if (enabledServices == null || !enabledServices.contains(myService)) {
208+
if (enabledServices == null || enabledServices.isEmpty()) {
209+
enabledServices = myService;
210+
} else {
211+
enabledServices += ":" + myService;
212+
}
213+
214+
// 这里可能会抛异常
215+
Settings.Secure.putString(getContentResolver(),
216+
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices);
217+
}
218+
} catch (SecurityException e) {
219+
// 没无障碍权限
220+
}
221+
198222
easyTierController = new EasyTierController(this, this);
199223
inForeground = true;
200224
initBitmapCache();
@@ -1454,6 +1478,13 @@ private void addContextMenuItems(ContextMenu menu, ComputerObject computer) {
14541478
menu.add(Menu.NONE, IPERF3_TEST_ID, 6, R.string.network_bandwidth_test);
14551479
menu.add(Menu.NONE, DELETE_ID, 6, R.string.pcview_menu_delete_pc);
14561480
menu.add(Menu.NONE, VIEW_DETAILS_ID, 7, R.string.pcview_menu_details);
1481+
1482+
// 添加IPv6开关选项,根据当前状态显示不同操作
1483+
if (details.ipv6Disabled) {
1484+
menu.add(Menu.NONE, DISABLE_IPV6_ID, 8, R.string.pcview_menu_enable_ipv6);
1485+
} else {
1486+
menu.add(Menu.NONE, DISABLE_IPV6_ID, 8, R.string.pcview_menu_disable_ipv6);
1487+
}
14571488
}
14581489

14591490
@Override
@@ -1515,6 +1546,9 @@ private boolean handleContextMenuAction(int itemId, ComputerObject computer) {
15151546
case GAMESTREAM_EOL_ID:
15161547
HelpLauncher.launchGameStreamEolFaq(this);
15171548
return true;
1549+
case DISABLE_IPV6_ID:
1550+
handleToggleIpv6Disabled(details);
1551+
return true;
15181552
default:
15191553
return false;
15201554
}
@@ -1581,6 +1615,43 @@ private void handleSecondaryScreen(ComputerDetails details) {
15811615
doSecondaryScreenStream(details);
15821616
}
15831617

1618+
private void handleToggleIpv6Disabled(ComputerDetails details) {
1619+
if (managerBinder == null) {
1620+
showToast(getString(R.string.error_manager_not_running));
1621+
return;
1622+
}
1623+
1624+
// 切换IPv6禁用状态
1625+
details.ipv6Disabled = !details.ipv6Disabled;
1626+
1627+
// 如果禁用了IPv6,清空所有IPv6相关地址
1628+
if (details.ipv6Disabled) {
1629+
details.ipv6Address = null;
1630+
1631+
// 如果activeAddress是IPv6,清空它
1632+
if (ComputerDetails.isIpv6Address(details.activeAddress)) {
1633+
details.activeAddress = null;
1634+
}
1635+
1636+
// 从availableAddresses中移除所有IPv6地址
1637+
if (details.availableAddresses != null) {
1638+
details.availableAddresses.removeIf(ComputerDetails::isIpv6Address);
1639+
}
1640+
}
1641+
1642+
// 更新数据库
1643+
managerBinder.updateComputer(details);
1644+
1645+
// 显示Toast提示用户当前状态
1646+
if (details.ipv6Disabled) {
1647+
showToast(getString(R.string.pcview_ipv6_disabled));
1648+
} else {
1649+
showToast(getString(R.string.pcview_ipv6_enabled));
1650+
}
1651+
// 刷新列表
1652+
startComputerUpdates();
1653+
}
1654+
15841655
// Adapter Fragment Callbacks
15851656

15861657
@Override

app/src/main/java/com/limelight/binding/input/KeyboardTranslator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener {
5555
public static final int VK_SEMICOLON = 59;
5656
public static final int VK_SLASH = 47;
5757
public static final int VK_SPACE = 32;
58-
public static final int VK_PRINTSCREEN = 154;
58+
// public static final int VK_PRINTSCREEN = 154;
59+
public static final int VK_PRINTSCREEN = 44;
5960
public static final int VK_TAB = 9;
6061
public static final int VK_LEFT = 37;
6162
public static final int VK_RIGHT = 39;

app/src/main/java/com/limelight/computers/ComputerDatabaseManager.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ private interface AddressFields {
3333
String REMOTE = "remote";
3434
String MANUAL = "manual";
3535
String IPv6 = "ipv6";
36+
String IPv6_DISABLED = "ipv6Disabled";
3637

3738
String ADDRESS = "address";
3839
String PORT = "port";
@@ -118,6 +119,7 @@ public boolean updateComputer(ComputerDetails details) {
118119
addresses.put(AddressFields.REMOTE, tupleToJson(details.remoteAddress));
119120
addresses.put(AddressFields.MANUAL, tupleToJson(details.manualAddress));
120121
addresses.put(AddressFields.IPv6, tupleToJson(details.ipv6Address));
122+
addresses.put(AddressFields.IPv6_DISABLED, details.ipv6Disabled);
121123
values.put(ADDRESSES_COLUMN_NAME, addresses.toString());
122124
} catch (JSONException e) {
123125
throw new RuntimeException(e);
@@ -149,6 +151,7 @@ private ComputerDetails getComputerFromCursor(Cursor c) {
149151
details.remoteAddress = tupleFromJson(addresses, AddressFields.REMOTE);
150152
details.manualAddress = tupleFromJson(addresses, AddressFields.MANUAL);
151153
details.ipv6Address = tupleFromJson(addresses, AddressFields.IPv6);
154+
details.ipv6Disabled = addresses.optBoolean(AddressFields.IPv6_DISABLED, false);
152155
} catch (JSONException e) {
153156
throw new RuntimeException(e);
154157
}

app/src/main/java/com/limelight/computers/ComputerManagerService.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,10 @@ public void removeComputer(ComputerDetails computer) {
266266
ComputerManagerService.this.removeComputer(computer);
267267
}
268268

269+
public void updateComputer(ComputerDetails computer) {
270+
ComputerManagerService.this.updateComputer(computer);
271+
}
272+
269273
public void stopPolling() {
270274
// Just call the unbind handler to cleanup
271275
ComputerManagerService.this.onUnbind(null);
@@ -526,6 +530,27 @@ public void removeComputer(ComputerDetails computer) {
526530
releaseLocalDatabaseReference();
527531
}
528532

533+
public void updateComputer(ComputerDetails computer) {
534+
if (!getLocalDatabaseReference()) {
535+
return;
536+
}
537+
538+
// Update the computer in the database
539+
dbManager.updateComputer(computer);
540+
541+
// Also update the in-memory copy
542+
synchronized (pollingTuples) {
543+
for (PollingTuple tuple : pollingTuples) {
544+
if (tuple.computer.uuid.equals(computer.uuid)) {
545+
tuple.computer.update(computer);
546+
break;
547+
}
548+
}
549+
}
550+
551+
releaseLocalDatabaseReference();
552+
}
553+
529554
private boolean getLocalDatabaseReference() {
530555
if (dbRefCount.get() == 0) {
531556
return false;

app/src/main/java/com/limelight/nvstream/http/ComputerDetails.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public String toString() {
6969
public AddressTuple ipv6Address;
7070
public String macAddress;
7171
public X509Certificate serverCert;
72+
public boolean ipv6Disabled;
7273

7374
// Transient attributes
7475
public State state;
@@ -133,7 +134,8 @@ public void update(ComputerDetails details) {
133134
if (details.manualAddress != null) {
134135
this.manualAddress = details.manualAddress;
135136
}
136-
if (details.ipv6Address != null) {
137+
// 如果已禁用 IPv6,则不更新 ipv6Address(保持为 null)
138+
if (details.ipv6Address != null && !this.ipv6Disabled) {
137139
this.ipv6Address = details.ipv6Address;
138140
}
139141
if (details.macAddress != null && !ZERO_MAC.equals(details.macAddress)) {
@@ -161,7 +163,12 @@ public void update(ComputerDetails details) {
161163

162164
public void addAvailableAddress(AddressTuple address) {
163165
if (address == null) return;
164-
166+
167+
// 如果禁用了IPv6,不添加IPv6地址
168+
if (ipv6Disabled && isIpv6Address(address)) {
169+
return;
170+
}
171+
165172
if (availableAddresses == null) {
166173
availableAddresses = new ArrayList<>();
167174
}
@@ -279,24 +286,33 @@ public AddressTuple selectBestAddress() {
279286
return selectFromLanAddresses(lanAddresses);
280287
}
281288

282-
// 其次选择IPv6地址
283-
if (ipv6Address != null && availableAddresses.contains(ipv6Address)) {
289+
// 其次选择IPv6地址(如果未禁用)
290+
if (!ipv6Disabled && ipv6Address != null && availableAddresses.contains(ipv6Address)) {
284291
return ipv6Address;
285292
}
286293

287294
// 最后选择公网地址
288295
if (remoteAddress != null && availableAddresses.contains(remoteAddress)) {
289296
return remoteAddress;
290297
}
291-
298+
299+
// 从剩余地址中选择第一个非IPv6地址(如果IPv6被禁用)
300+
if (ipv6Disabled) {
301+
for (AddressTuple address : availableAddresses) {
302+
if (!isIpv6Address(address)) {
303+
return address;
304+
}
305+
}
306+
}
307+
292308
return availableAddresses.get(0);
293309
}
294310

295311
private AddressTuple selectBestAddressFromFields() {
296312
if (localAddress != null && isLanIpv4Address(localAddress)) {
297313
return localAddress;
298314
}
299-
if (ipv6Address != null) {
315+
if (!ipv6Disabled && ipv6Address != null) {
300316
return ipv6Address;
301317
}
302318
if (remoteAddress != null) {
@@ -336,7 +352,7 @@ public String toString() {
336352
str.append("UUID: ").append(uuid).append("\n");
337353
str.append("Local Address: ").append(localAddress).append("\n");
338354
str.append("Remote Address: ").append(remoteAddress).append("\n");
339-
str.append("IPv6 Address: ").append(ipv6Address).append("\n");
355+
str.append("IPv6 Address: ").append(ipv6Disabled ? "Disabled" : ipv6Address).append("\n");
340356
str.append("Manual Address: ").append(manualAddress).append("\n");
341357
str.append("MAC Address: ").append(macAddress).append("\n");
342358
str.append("Pair State: ").append(pairState).append("\n");

app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,12 @@ public enum PerfOverlayPosition {
233233

234234
private static final boolean DEFAULT_ENABLE_LOCAL_CURSOR_RENDERING = true;
235235
public boolean enableLocalCursorRendering;
236+
//自定义按键映射
237+
public boolean enableCustomKeyMap;
238+
//修复鼠标中键识别
239+
public boolean fixMouseMiddle;
240+
//修复本地鼠标滚轮识别
241+
public boolean fixMouseWheel;
236242
public static final int FRAME_PACING_MIN_LATENCY = 0;
237243
public static final int FRAME_PACING_BALANCED = 1;
238244
public static final int FRAME_PACING_CAP_FPS = 2;
@@ -786,6 +792,9 @@ else if (audioConfig.equals("51")) {
786792
config.enableDoubleClickDrag = prefs.getBoolean(ENABLE_DOUBLE_CLICK_DRAG_PREF_STRING, DEFAULT_ENABLE_DOUBLE_CLICK_DRAG);
787793
config.doubleTapTimeThreshold = prefs.getInt(DOUBLE_TAP_TIME_THRESHOLD_PREF_STRING, DEFAULT_DOUBLE_TAP_TIME_THRESHOLD);
788794
config.enableLocalCursorRendering = prefs.getBoolean(ENABLE_LOCAL_CURSOR_RENDERING_PREF_STRING, DEFAULT_ENABLE_LOCAL_CURSOR_RENDERING);
795+
config.enableCustomKeyMap=prefs.getBoolean("checkbox_special_key_map",false);
796+
config.fixMouseMiddle=prefs.getBoolean("checkbox_mouse_middle",false);
797+
config.fixMouseWheel=prefs.getBoolean("checkbox_mouse_wheel",false);
789798
config.enableSops = prefs.getBoolean(SOPS_PREF_STRING, DEFAULT_SOPS);
790799
config.stretchVideo = prefs.getBoolean(STRETCH_PREF_STRING, DEFAULT_STRETCH);
791800
config.playHostAudio = prefs.getBoolean(HOST_AUDIO_PREF_STRING, DEFAULT_HOST_AUDIO);

app/src/main/java/com/limelight/services/KeyboardAccessibilityService.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,17 @@
22

33
import android.accessibilityservice.AccessibilityService;
44
import android.accessibilityservice.AccessibilityServiceInfo;
5+
import android.text.TextUtils;
56
import android.util.Log;
67
import android.view.KeyEvent;
78
import android.view.accessibility.AccessibilityEvent;
89

10+
import com.limelight.Game;
11+
import com.limelight.preferences.PreferenceConfiguration;
12+
13+
import org.json.JSONArray;
14+
import org.json.JSONObject;
15+
916
/**
1017
* 一个无障碍服务,用于在系统级别拦截硬件键盘事件。
1118
* 主要目的是捕获像 Win 键、Alt+Tab 等被 Android 系统默认行为占用的按键,
@@ -78,6 +85,47 @@ protected void onServiceConnected() {
7885
*/
7986
@Override
8087
protected boolean onKeyEvent(KeyEvent event) {
88+
if (interceptingEnabled && PreferenceConfiguration.readPreferences(this).enableCustomKeyMap) {
89+
int fixedKeyCode = event.getKeyCode();
90+
switch(fixedKeyCode){
91+
case KeyEvent.KEYCODE_HOME:
92+
// HOME键映射ESC
93+
fixedKeyCode = KeyEvent.KEYCODE_ESCAPE;
94+
break;
95+
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
96+
// 安卓上一首键映射Windows F5键
97+
fixedKeyCode = KeyEvent.KEYCODE_F5;
98+
break;
99+
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
100+
// 安卓播放暂停键映射Windows F10键
101+
fixedKeyCode = KeyEvent.KEYCODE_F10;
102+
break;
103+
case KeyEvent.KEYCODE_MEDIA_NEXT:
104+
// 安卓下一首键映射Windows F11键
105+
fixedKeyCode = KeyEvent.KEYCODE_F11;
106+
break;
107+
}
108+
// 安卓截图键映射Windows PRINT SCREEN键
109+
if(fixedKeyCode == KeyEvent.KEYCODE_SYSRQ || fixedKeyCode != event.getKeyCode()) {
110+
if (keyEventCallback != null) {
111+
KeyEvent fixedEvent = new KeyEvent(
112+
event.getDownTime(),
113+
event.getEventTime(),
114+
event.getAction(),
115+
fixedKeyCode,
116+
event.getRepeatCount(),
117+
event.getMetaState(),
118+
event.getDeviceId(),
119+
event.getScanCode(),
120+
event.getFlags(),
121+
event.getSource()
122+
);
123+
keyEventCallback.onKeyEvent(fixedEvent);
124+
}
125+
return true;
126+
}
127+
}
128+
81129
// 小米平板将物理 ESC 键(ScanCode=1)映射为 Android 的 BACK 键(Code=4)。
82130
// 必须在下方的 switch-case 过滤之前进行拦截,否则会被当作普通返回键忽略。
83131
if (event.getScanCode() == 1) {

app/src/main/res/values-zh-rCN/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
<string name="pcview_menu_secondary_screen"> 作为副屏串流(基地适用) </string>
2020
<string name="pcview_menu_sleep_success"> 已催促主机睡眠 </string>
2121
<string name="pcview_menu_sleep_fail"> 连接主机睡眠失败 </string>
22+
<string name="pcview_menu_disable_ipv6">禁用 IPv6</string>
23+
<string name="pcview_menu_enable_ipv6">启用 IPv6</string>
24+
<string name="pcview_ipv6_disabled">已禁用此电脑的 IPv6 连接</string>
25+
<string name="pcview_ipv6_enabled">已启用此电脑的 IPv6 连接</string>
2226
<!-- Pair messages -->
2327
<string name="pairing"> 配对中…… </string>
2428
<string name="pair_pc_offline"> 电脑离线中 </string>

app/src/main/res/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
<string name="pcview_menu_eol">NVIDIA GameStream End-of-Service</string>
2929
<string name="pcview_menu_sleep_success">Host sleep success</string>
3030
<string name="pcview_menu_sleep_fail">Host sleep failed</string>
31+
<string name="pcview_menu_disable_ipv6">Disable IPv6</string>
32+
<string name="pcview_menu_enable_ipv6">Enable IPv6</string>
33+
<string name="pcview_ipv6_disabled">IPv6 disabled for this PC</string>
34+
<string name="pcview_ipv6_enabled">IPv6 enabled for this PC</string>
3135

3236
<!-- Network test strings -->
3337
<string name="nettest_title_waiting">Testing Network Connection</string>

0 commit comments

Comments
 (0)