mirror of https://github.com/jetkvm/kvm.git
				
				
				
			add jsonrpc keyboard macro get/set
This commit is contained in:
		
							parent
							
								
									1f8f885a1d
								
							
						
					
					
						commit
						5650bad796
					
				
							
								
								
									
										61
									
								
								config.go
								
								
								
								
							
							
						
						
									
										61
									
								
								config.go
								
								
								
								
							| 
						 | 
					@ -14,6 +14,65 @@ type WakeOnLanDevice struct {
 | 
				
			||||||
	MacAddress string `json:"macAddress"`
 | 
						MacAddress string `json:"macAddress"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Constants for keyboard macro limits
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						MaxMacrosPerDevice = 25
 | 
				
			||||||
 | 
						MaxStepsPerMacro   = 10
 | 
				
			||||||
 | 
						MaxKeysPerStep     = 10
 | 
				
			||||||
 | 
						MinStepDelay       = 50
 | 
				
			||||||
 | 
						MaxStepDelay       = 2000
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type KeyboardMacroStep struct {
 | 
				
			||||||
 | 
						Keys      []string `json:"keys"`
 | 
				
			||||||
 | 
						Modifiers []string `json:"modifiers"`
 | 
				
			||||||
 | 
						Delay     int      `json:"delay"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *KeyboardMacroStep) Validate() error {
 | 
				
			||||||
 | 
						if len(s.Keys) > MaxKeysPerStep {
 | 
				
			||||||
 | 
							return fmt.Errorf("too many keys in step (max %d)", MaxKeysPerStep)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if s.Delay < MinStepDelay {
 | 
				
			||||||
 | 
							s.Delay = MinStepDelay
 | 
				
			||||||
 | 
						} else if s.Delay > MaxStepDelay {
 | 
				
			||||||
 | 
							s.Delay = MaxStepDelay
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type KeyboardMacro struct {
 | 
				
			||||||
 | 
						ID          string              `json:"id"`
 | 
				
			||||||
 | 
						Name        string              `json:"name"`
 | 
				
			||||||
 | 
						Description string              `json:"description,omitempty"`
 | 
				
			||||||
 | 
						Steps       []KeyboardMacroStep `json:"steps"`
 | 
				
			||||||
 | 
						SortOrder   int                 `json:"sortOrder,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *KeyboardMacro) Validate() error {
 | 
				
			||||||
 | 
						if m.Name == "" {
 | 
				
			||||||
 | 
							return fmt.Errorf("macro name cannot be empty")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(m.Steps) == 0 {
 | 
				
			||||||
 | 
							return fmt.Errorf("macro must have at least one step")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(m.Steps) > MaxStepsPerMacro {
 | 
				
			||||||
 | 
							m.Steps = m.Steps[:MaxStepsPerMacro]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := range m.Steps {
 | 
				
			||||||
 | 
							if err := m.Steps[i].Validate(); err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("invalid step %d: %w", i+1, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Config struct {
 | 
					type Config struct {
 | 
				
			||||||
	CloudURL             string             `json:"cloud_url"`
 | 
						CloudURL             string             `json:"cloud_url"`
 | 
				
			||||||
	CloudAppURL          string             `json:"cloud_app_url"`
 | 
						CloudAppURL          string             `json:"cloud_app_url"`
 | 
				
			||||||
| 
						 | 
					@ -26,6 +85,7 @@ type Config struct {
 | 
				
			||||||
	LocalAuthToken       string             `json:"local_auth_token"`
 | 
						LocalAuthToken       string             `json:"local_auth_token"`
 | 
				
			||||||
	LocalAuthMode        string             `json:"localAuthMode"` //TODO: fix it with migration
 | 
						LocalAuthMode        string             `json:"localAuthMode"` //TODO: fix it with migration
 | 
				
			||||||
	WakeOnLanDevices     []WakeOnLanDevice  `json:"wake_on_lan_devices"`
 | 
						WakeOnLanDevices     []WakeOnLanDevice  `json:"wake_on_lan_devices"`
 | 
				
			||||||
 | 
						KeyboardMacros       []KeyboardMacro    `json:"keyboard_macros"`
 | 
				
			||||||
	EdidString           string             `json:"hdmi_edid_string"`
 | 
						EdidString           string             `json:"hdmi_edid_string"`
 | 
				
			||||||
	ActiveExtension      string             `json:"active_extension"`
 | 
						ActiveExtension      string             `json:"active_extension"`
 | 
				
			||||||
	DisplayMaxBrightness int                `json:"display_max_brightness"`
 | 
						DisplayMaxBrightness int                `json:"display_max_brightness"`
 | 
				
			||||||
| 
						 | 
					@ -43,6 +103,7 @@ var defaultConfig = &Config{
 | 
				
			||||||
	CloudAppURL:          "https://app.jetkvm.com",
 | 
						CloudAppURL:          "https://app.jetkvm.com",
 | 
				
			||||||
	AutoUpdateEnabled:    true, // Set a default value
 | 
						AutoUpdateEnabled:    true, // Set a default value
 | 
				
			||||||
	ActiveExtension:      "",
 | 
						ActiveExtension:      "",
 | 
				
			||||||
 | 
						KeyboardMacros:       []KeyboardMacro{},
 | 
				
			||||||
	DisplayMaxBrightness: 64,
 | 
						DisplayMaxBrightness: 64,
 | 
				
			||||||
	DisplayDimAfterSec:   120,  // 2 minutes
 | 
						DisplayDimAfterSec:   120,  // 2 minutes
 | 
				
			||||||
	DisplayOffAfterSec:   1800, // 30 minutes
 | 
						DisplayOffAfterSec:   1800, // 30 minutes
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										97
									
								
								jsonrpc.go
								
								
								
								
							
							
						
						
									
										97
									
								
								jsonrpc.go
								
								
								
								
							| 
						 | 
					@ -792,6 +792,101 @@ func rpcSetScrollSensitivity(sensitivity string) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getKeyboardMacros() (interface{}, error) {
 | 
				
			||||||
 | 
						macros := make([]KeyboardMacro, len(config.KeyboardMacros))
 | 
				
			||||||
 | 
						copy(macros, config.KeyboardMacros)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return macros, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type KeyboardMacrosParams struct {
 | 
				
			||||||
 | 
						Macros []interface{} `json:"macros"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func setKeyboardMacros(params KeyboardMacrosParams) (interface{}, error) {
 | 
				
			||||||
 | 
						if params.Macros == nil {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("missing or invalid macros parameter")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						newMacros := make([]KeyboardMacro, 0, len(params.Macros))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, item := range params.Macros {
 | 
				
			||||||
 | 
							macroMap, ok := item.(map[string]interface{})
 | 
				
			||||||
 | 
							if !ok {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("invalid macro at index %d", i)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							id, _ := macroMap["id"].(string)
 | 
				
			||||||
 | 
							if id == "" {
 | 
				
			||||||
 | 
								id = fmt.Sprintf("macro-%d", time.Now().UnixNano())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							name, _ := macroMap["name"].(string)
 | 
				
			||||||
 | 
							description, _ := macroMap["description"].(string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sortOrder := i + 1
 | 
				
			||||||
 | 
							if sortOrderFloat, ok := macroMap["sortOrder"].(float64); ok {
 | 
				
			||||||
 | 
								sortOrder = int(sortOrderFloat)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							steps := []KeyboardMacroStep{}
 | 
				
			||||||
 | 
							if stepsArray, ok := macroMap["steps"].([]interface{}); ok {
 | 
				
			||||||
 | 
								for _, stepItem := range stepsArray {
 | 
				
			||||||
 | 
									stepMap, ok := stepItem.(map[string]interface{})
 | 
				
			||||||
 | 
									if !ok {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									step := KeyboardMacroStep{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if keysArray, ok := stepMap["keys"].([]interface{}); ok {
 | 
				
			||||||
 | 
										for _, k := range keysArray {
 | 
				
			||||||
 | 
											if keyStr, ok := k.(string); ok {
 | 
				
			||||||
 | 
												step.Keys = append(step.Keys, keyStr)
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if modsArray, ok := stepMap["modifiers"].([]interface{}); ok {
 | 
				
			||||||
 | 
										for _, m := range modsArray {
 | 
				
			||||||
 | 
											if modStr, ok := m.(string); ok {
 | 
				
			||||||
 | 
												step.Modifiers = append(step.Modifiers, modStr)
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if delay, ok := stepMap["delay"].(float64); ok {
 | 
				
			||||||
 | 
										step.Delay = int(delay)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									steps = append(steps, step)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							macro := KeyboardMacro{
 | 
				
			||||||
 | 
								ID:          id,
 | 
				
			||||||
 | 
								Name:        name,
 | 
				
			||||||
 | 
								Description: description,
 | 
				
			||||||
 | 
								Steps:       steps,
 | 
				
			||||||
 | 
								SortOrder:   sortOrder,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err := macro.Validate(); err != nil {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("invalid macro at index %d: %w", i, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							newMacros = append(newMacros, macro)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						config.KeyboardMacros = newMacros
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := SaveConfig(); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var rpcHandlers = map[string]RPCHandler{
 | 
					var rpcHandlers = map[string]RPCHandler{
 | 
				
			||||||
	"ping":                   {Func: rpcPing},
 | 
						"ping":                   {Func: rpcPing},
 | 
				
			||||||
	"getDeviceID":            {Func: rpcGetDeviceID},
 | 
						"getDeviceID":            {Func: rpcGetDeviceID},
 | 
				
			||||||
| 
						 | 
					@ -857,4 +952,6 @@ var rpcHandlers = map[string]RPCHandler{
 | 
				
			||||||
	"setCloudUrl":            {Func: rpcSetCloudUrl, Params: []string{"apiUrl", "appUrl"}},
 | 
						"setCloudUrl":            {Func: rpcSetCloudUrl, Params: []string{"apiUrl", "appUrl"}},
 | 
				
			||||||
	"getScrollSensitivity":   {Func: rpcGetScrollSensitivity},
 | 
						"getScrollSensitivity":   {Func: rpcGetScrollSensitivity},
 | 
				
			||||||
	"setScrollSensitivity":   {Func: rpcSetScrollSensitivity, Params: []string{"sensitivity"}},
 | 
						"setScrollSensitivity":   {Func: rpcSetScrollSensitivity, Params: []string{"sensitivity"}},
 | 
				
			||||||
 | 
						"getKeyboardMacros":      {Func: getKeyboardMacros},
 | 
				
			||||||
 | 
						"setKeyboardMacros":      {Func: setKeyboardMacros, Params: []string{"params"}},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue