Skip to content

Commit 94f36d0

Browse files
authored
Merge branch 'dev' into paste-text-keyboard-layouts
2 parents 22566e0 + 77b4c1c commit 94f36d0

File tree

7 files changed

+109
-23
lines changed

7 files changed

+109
-23
lines changed

config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ type Config struct {
9090
KeyboardLayout string `json:"keyboard_layout"`
9191
EdidString string `json:"hdmi_edid_string"`
9292
ActiveExtension string `json:"active_extension"`
93+
DisplayRotation string `json:"display_rotation"`
9394
DisplayMaxBrightness int `json:"display_max_brightness"`
9495
DisplayDimAfterSec int `json:"display_dim_after_sec"`
9596
DisplayOffAfterSec int `json:"display_off_after_sec"`
@@ -109,6 +110,7 @@ var defaultConfig = &Config{
109110
ActiveExtension: "",
110111
KeyboardMacros: []KeyboardMacro{},
111112
KeyboardLayout: "en_US",
113+
DisplayRotation: "270",
112114
DisplayMaxBrightness: 64,
113115
DisplayDimAfterSec: 120, // 2 minutes
114116
DisplayOffAfterSec: 1800, // 30 minutes

display.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ func lvImgSetSrc(objName string, src string) (*CtrlResponse, error) {
7373
return CallCtrlAction("lv_img_set_src", map[string]interface{}{"obj": objName, "src": src})
7474
}
7575

76+
func lvDispSetRotation(rotation string) (*CtrlResponse, error) {
77+
return CallCtrlAction("lv_disp_set_rotation", map[string]interface{}{"rotation": rotation})
78+
}
79+
7680
func updateLabelIfChanged(objName string, newText string) {
7781
if newText != "" && newText != displayedTexts[objName] {
7882
_, _ = lvLabelSetText(objName, newText)
@@ -373,6 +377,7 @@ func init() {
373377
waitCtrlClientConnected()
374378
displayLogger.Info().Msg("setting initial display contents")
375379
time.Sleep(500 * time.Millisecond)
380+
_, _ = lvDispSetRotation(config.DisplayRotation)
376381
updateStaticContents()
377382
displayInited = true
378383
displayLogger.Info().Msg("display inited")

internal/timesync/ntp.go

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ var defaultNTPServers = []string{
1313
"time.aws.com",
1414
"time.windows.com",
1515
"time.google.com",
16-
"162.159.200.123", // time.cloudflare.com
16+
"162.159.200.123", // time.cloudflare.com IPv4
17+
"2606:4700:f1::123", // time.cloudflare.com IPv6
1718
"0.pool.ntp.org",
1819
"1.pool.ntp.org",
1920
"2.pool.ntp.org",
@@ -57,6 +58,13 @@ func (t *TimeSync) queryMultipleNTP(servers []string, timeout time.Duration) (no
5758

5859
// query the server
5960
now, response, err := queryNtpServer(server, timeout)
61+
if err != nil {
62+
scopedLogger.Warn().
63+
Str("error", err.Error()).
64+
Msg("failed to query NTP server")
65+
results <- nil
66+
return
67+
}
6068

6169
// set the last RTT
6270
metricNtpServerLastRTT.WithLabelValues(
@@ -76,32 +84,33 @@ func (t *TimeSync) queryMultipleNTP(servers []string, timeout time.Duration) (no
7684
strconv.Itoa(int(response.Precision)),
7785
).Set(1)
7886

79-
if err == nil {
80-
// increase success count
81-
metricNtpTotalSuccessCount.Inc()
82-
metricNtpSuccessCount.WithLabelValues(server).Inc()
83-
84-
scopedLogger.Info().
85-
Str("time", now.Format(time.RFC3339)).
86-
Str("reference", response.ReferenceString()).
87-
Str("rtt", response.RTT.String()).
88-
Str("clockOffset", response.ClockOffset.String()).
89-
Uint8("stratum", response.Stratum).
90-
Msg("NTP server returned time")
91-
results <- &ntpResult{
92-
now: now,
93-
offset: &response.ClockOffset,
94-
}
95-
} else {
96-
scopedLogger.Warn().
97-
Str("error", err.Error()).
98-
Msg("failed to query NTP server")
87+
// increase success count
88+
metricNtpTotalSuccessCount.Inc()
89+
metricNtpSuccessCount.WithLabelValues(server).Inc()
90+
91+
scopedLogger.Info().
92+
Str("time", now.Format(time.RFC3339)).
93+
Str("reference", response.ReferenceString()).
94+
Str("rtt", response.RTT.String()).
95+
Str("clockOffset", response.ClockOffset.String()).
96+
Uint8("stratum", response.Stratum).
97+
Msg("NTP server returned time")
98+
results <- &ntpResult{
99+
now: now,
100+
offset: &response.ClockOffset,
99101
}
100102
}(server)
101103
}
102104

103-
result := <-results
104-
return result.now, result.offset
105+
for range servers {
106+
result := <-results
107+
if result == nil {
108+
continue
109+
}
110+
now, offset = result.now, result.offset
111+
return
112+
}
113+
return
105114
}
106115

107116
func queryNtpServer(server string, timeout time.Duration) (now *time.Time, response *ntp.Response, err error) {

internal/usbgadget/hid_mouse_absolute.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ var absoluteMouseCombinedReportDesc = []byte{
5555
0x09, 0x38, // Usage (Wheel)
5656
0x15, 0x81, // Logical Minimum (-127)
5757
0x25, 0x7F, // Logical Maximum (127)
58+
0x35, 0x00, // Physical Minimum (0) = Reset Physical Minimum
59+
0x45, 0x00, // Physical Maximum (0) = Reset Physical Maximum
5860
0x75, 0x08, // Report Size (8)
5961
0x95, 0x01, // Report Count (1)
6062
0x81, 0x06, // Input (Data, Var, Rel)

jsonrpc.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ type JSONRPCEvent struct {
3838
Params interface{} `json:"params,omitempty"`
3939
}
4040

41+
type DisplayRotationSettings struct {
42+
Rotation string `json:"rotation"`
43+
}
44+
4145
type BacklightSettings struct {
4246
MaxBrightness int `json:"max_brightness"`
4347
DimAfter int `json:"dim_after"`
@@ -280,6 +284,24 @@ func rpcTryUpdate() error {
280284
return nil
281285
}
282286

287+
func rpcSetDisplayRotation(params DisplayRotationSettings) error {
288+
var err error
289+
_, err = lvDispSetRotation(params.Rotation)
290+
if err == nil {
291+
config.DisplayRotation = params.Rotation
292+
if err := SaveConfig(); err != nil {
293+
return fmt.Errorf("failed to save config: %w", err)
294+
}
295+
}
296+
return err
297+
}
298+
299+
func rpcGetDisplayRotation() (*DisplayRotationSettings, error) {
300+
return &DisplayRotationSettings{
301+
Rotation: config.DisplayRotation,
302+
}, nil
303+
}
304+
283305
func rpcSetBacklightSettings(params BacklightSettings) error {
284306
blConfig := params
285307

@@ -1024,6 +1046,8 @@ var rpcHandlers = map[string]RPCHandler{
10241046
"getWakeOnLanDevices": {Func: rpcGetWakeOnLanDevices},
10251047
"setWakeOnLanDevices": {Func: rpcSetWakeOnLanDevices, Params: []string{"params"}},
10261048
"resetConfig": {Func: rpcResetConfig},
1049+
"setDisplayRotation": {Func: rpcSetDisplayRotation, Params: []string{"params"}},
1050+
"getDisplayRotation": {Func: rpcGetDisplayRotation},
10271051
"setBacklightSettings": {Func: rpcSetBacklightSettings, Params: []string{"params"}},
10281052
"getBacklightSettings": {Func: rpcGetBacklightSettings},
10291053
"getDCPowerState": {Func: rpcGetDCPowerState},

ui/src/hooks/stores.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,9 @@ interface SettingsState {
292292
developerMode: boolean;
293293
setDeveloperMode: (enabled: boolean) => void;
294294

295+
displayRotation: string;
296+
setDisplayRotation: (rotation: string) => void;
297+
295298
backlightSettings: BacklightSettings;
296299
setBacklightSettings: (settings: BacklightSettings) => void;
297300
}
@@ -312,6 +315,10 @@ export const useSettingsStore = create(
312315
developerMode: false,
313316
setDeveloperMode: enabled => set({ developerMode: enabled }),
314317

318+
displayRotation: "270",
319+
setDisplayRotation: (rotation: string) =>
320+
set({ displayRotation: rotation }),
321+
315322
backlightSettings: {
316323
max_brightness: 100,
317324
dim_after: 10000,

ui/src/routes/devices.$id.settings.hardware.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,25 @@ export default function SettingsHardwareRoute() {
1515
const [send] = useJsonRpc();
1616
const settings = useSettingsStore();
1717

18+
const setDisplayRotation = useSettingsStore(state => state.setDisplayRotation);
19+
20+
const handleDisplayRotationChange = (rotation: string) => {
21+
setDisplayRotation(rotation);
22+
handleDisplayRotationSave();
23+
};
24+
25+
const handleDisplayRotationSave = () => {
26+
send("setDisplayRotation", { params: { rotation: settings.displayRotation } }, resp => {
27+
if ("error" in resp) {
28+
notifications.error(
29+
`Failed to set display orientation: ${resp.error.data || "Unknown error"}`,
30+
);
31+
return;
32+
}
33+
notifications.success("Display orientation updated successfully");
34+
});
35+
};
36+
1837
const setBacklightSettings = useSettingsStore(state => state.setBacklightSettings);
1938

2039
const handleBacklightSettingsChange = (settings: BacklightSettings) => {
@@ -59,6 +78,24 @@ export default function SettingsHardwareRoute() {
5978
description="Configure display settings and hardware options for your JetKVM device"
6079
/>
6180
<div className="space-y-4">
81+
<SettingsItem
82+
title="Display Orientation"
83+
description="Set the orientation of the display"
84+
>
85+
<SelectMenuBasic
86+
size="SM"
87+
label=""
88+
value={settings.displayRotation.toString()}
89+
options={[
90+
{ value: "270", label: "Normal" },
91+
{ value: "90", label: "Inverted" },
92+
]}
93+
onChange={e => {
94+
settings.displayRotation = e.target.value;
95+
handleDisplayRotationChange(settings.displayRotation);
96+
}}
97+
/>
98+
</SettingsItem>
6299
<SettingsItem
63100
title="Display Brightness"
64101
description="Set the brightness of the display"

0 commit comments

Comments
 (0)