• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "input_method_manager_command.h"
17 #include <getopt.h>
18 #include <iostream>
19 
20 #include "input_method_controller.h"
21 
22 namespace OHOS {
23 namespace MiscServices {
24 
EnabledStatusToString(EnabledStatus status)25 static std::string EnabledStatusToString(EnabledStatus status)
26 {
27     switch (status) {
28         case EnabledStatus::DISABLED:
29             return "DISABLED";
30         case EnabledStatus::BASIC_MODE:
31             return "BASIC_MODE";
32         case EnabledStatus::FULL_EXPERIENCE_MODE:
33             return "FULL_EXPERIENCE_MODE";
34         default:
35             return "UNKNOWN";
36     }
37 }
38 
ValidateImeExists(const std::string & bundle)39 bool ValidateImeExists(const std::string& bundle)
40 {
41     std::vector<Property> methods;
42     auto controller = InputMethodController::GetInstance();
43     if (controller == nullptr) {
44         std::cout << "Error: InputMethodController instance is null." << std::endl;
45         return false;
46     }
47     controller->ListInputMethod(methods);
48     for (const auto& m : methods) {
49         if (m.name == bundle) {
50             return true;
51         }
52     }
53     std::cout << "Error: The input method does not exist." << std::endl;
54     return false;
55 }
56 
GetBundleName(const char * optarg)57 std::string GetBundleName(const char* optarg)
58 {
59     constexpr int32_t MAX_OPTIONS_STR_LEN = 128; // related to budleName max len
60     if (optarg == nullptr) {
61         std::cout << "Error: Invalid argument!" << std::endl;
62         return "";
63     }
64     if (strnlen(optarg, MAX_OPTIONS_STR_LEN + 1) > MAX_OPTIONS_STR_LEN) {
65         std::cout << "Error: Invalid argument!" << std::endl;
66         return "";
67     }
68     std::string bundleName(optarg);
69     if (bundleName.empty()) {
70         std::cout << "Error: Invalid argument!" << std::endl;
71         return "";
72     }
73     return bundleName;
74 }
75 
HandleStatusChange(const char * optarg,int32_t argc,char * argv[],EnabledStatus status,const std::string & successMsg)76 void HandleStatusChange(const char* optarg, int32_t argc, char *argv[], EnabledStatus status,
77                         const std::string& successMsg)
78 {
79     std::string bundleName = GetBundleName(optarg);
80     if (bundleName.empty()) {
81         return;
82     }
83     if (!ValidateImeExists(bundleName)) {
84         return;
85     }
86 
87     if (status == EnabledStatus::BASIC_MODE && optind < argc) {
88         if (optind + 1 == argc) {
89             std::string nextArg = argv[optind];
90             if (nextArg == "-b" || nextArg == "-f") {
91                 status = (nextArg == "-f") ? EnabledStatus::FULL_EXPERIENCE_MODE : EnabledStatus::BASIC_MODE;
92                 optind++;
93             } else {
94                 std::cout << "Error: Invalid mode after -e. Use -b or -f" << std::endl;
95                 return;
96             }
97         } else if (optind + 1 > argc) {
98             status = EnabledStatus::BASIC_MODE;
99         } else {
100             std::cout << "Error: Invalid mode after -e. Use -b or -f" << std::endl;
101             return;
102         }
103     }
104 
105     if (status == EnabledStatus::DISABLED && optind < argc) {
106         std::cout << "Error: Invalid command!" << std::endl;
107         return;
108     }
109     auto controller = InputMethodController::GetInstance();
110     if (controller == nullptr) {
111         std::cout << "Error: InputMethodController instance is null." << std::endl;
112         return;
113     }
114     auto ret = controller->EnableIme(bundleName, "", status);
115     if (ret == ErrorCode::NO_ERROR) {
116         std::cout << successMsg << ". status:" << EnabledStatusToString(status) << std::endl;
117     } else {
118         std::cout << "Error: Operation failed.Error code:" << ret << std::endl;
119     }
120 }
121 
HandleSwitchIme(const char * optarg)122 void HandleSwitchIme(const char* optarg)
123 {
124     std::string bundleName = GetBundleName(optarg);
125     if (bundleName.empty()) {
126         return;
127     }
128     if (!ValidateImeExists(bundleName)) {
129         return;
130     }
131     auto controller = InputMethodController::GetInstance();
132     if (controller == nullptr) {
133         std::cout << "Error: InputMethodController instance is null." << std::endl;
134         return;
135     }
136     int32_t ret = controller->SwitchInputMethod(SwitchTrigger::NATIVE_SA, bundleName);
137     if (ret == 0) {
138         std::cout << "Succeeded in switching the input method. IME:" << bundleName << std::endl;
139     } else {
140         std::cout << "Error: Operation failed. Error code:" << ret << std::endl;
141     }
142 }
143 
HandleGetCurrentIme(int32_t argc)144 void HandleGetCurrentIme(int32_t argc)
145 {
146     if (optind < argc) {
147         std::cout << "Error: Invalid command!" << std::endl;
148         return;
149     }
150     auto controller = InputMethodController::GetInstance();
151     if (controller == nullptr) {
152         std::cout << "Error: InputMethodController instance is null." << std::endl;
153         return;
154     }
155     auto propertyData = controller->GetCurrentInputMethod();
156     if (propertyData != nullptr) {
157         std::cout << "The current input method is: " << propertyData->name << ", status: "
158                   << EnabledStatusToString(propertyData->status) << std::endl;
159     } else {
160         std::cout << "Error: can not get current input method." << std::endl;
161     }
162 }
163 
HandleListIme(int32_t argc)164 void HandleListIme(int32_t argc)
165 {
166     if (optind < argc) {
167         std::cout << "Error: Invalid command!" << std::endl;
168         return;
169     }
170     auto controller = InputMethodController::GetInstance();
171     if (controller == nullptr) {
172         std::cout << "Error: InputMethodController instance is null." << std::endl;
173         return;
174     }
175     std::vector<Property> methods;
176     auto ret = controller->ListInputMethod(methods);
177     if (ret != ErrorCode::NO_ERROR) {
178         std::cout << "Error: list input method failed. Error code:" << ret << std::endl;
179         return;
180     }
181     std::shared_ptr<Property> property;
182     ret = controller->GetDefaultInputMethod(property);
183     if (property == nullptr) {
184         std::cout << "Error: list input method failed. Error code:" << ret << std::endl;
185         return;
186     }
187     for (const auto& m : methods) {
188         if (m.name == property->name) {
189             std::cout << "bundle: " << m.name << std::endl;
190             continue;
191         }
192         std::cout << "bundle: " << m.name << ", status: " << EnabledStatusToString(m.status) << std::endl;
193     }
194 }
195 
ParseCommand(int32_t argc,char * argv[])196 int32_t InputMethodManagerCommand::ParseCommand(int32_t argc, char *argv[])
197 {
198     int32_t optCode = 0;
199     while ((optCode = getopt(argc, argv, "d:e:ghls:")) != -1) {
200         switch (optCode) {
201             case 'e':
202                 HandleStatusChange(optarg, argc, argv, EnabledStatus::BASIC_MODE, "Succeeded in enabling IME");
203                 return ErrorCode::NO_ERROR;
204             case 'd':
205                 HandleStatusChange(optarg, argc, argv, EnabledStatus::DISABLED, "Succeeded in disabling IME");
206                 return ErrorCode::NO_ERROR;
207             case 's':
208                 HandleSwitchIme(optarg);
209                 return ErrorCode::NO_ERROR;
210             case 'g':
211                 HandleGetCurrentIme(argc);
212                 return ErrorCode::NO_ERROR;
213             case 'l':
214                 HandleListIme(argc);
215                 return ErrorCode::NO_ERROR;
216             case 'h':
217                 ShowUsage(argc);
218                 return ErrorCode::NO_ERROR;
219             case '?':
220                 ShowUsage(argc);
221                 return ErrorCode::NO_ERROR;
222             default:
223                 return ErrorCode::NO_ERROR;
224         }
225     }
226     return ErrorCode::NO_ERROR;
227 }
228 
ShowUsage(int32_t argc)229 void InputMethodManagerCommand::ShowUsage(int32_t argc)
230 {
231     if (optind < argc) {
232         std::cout << "Error: Invalid command!" << std::endl;
233         return;
234     }
235     std::cout << "\nInput Method Manager Command Line Tool\n"
236               << "Usage: ime [OPTION] [ARGUMENT]\n\n"
237               << "Options:\n"
238               << "  -e <bundle> [-b | -f] Enable the specified input method to specified mode.\n"
239               << "                        If the -b/-f option is not set, the default value is -b.\n"
240               << "                        Current operation cannot be applied to the preconfigured"
241               << " default input method.\n"
242               << "  -d <bundle>           Disable the specified input method.\n"
243               << "  -s <bundle>           Switch to the specified input method.\n"
244               << "                        In the lock screen or password input box scenario,"
245               << " switching to other input methods is not allowed.\n"
246               << "  -g                    Get current input method.\n"
247               << "  -l                    List all input methods.\n"
248               << "  -h                    Show this help message.\n";
249 }
250 } // namespace MiscServices
251 } // namespace OHOS